diff --git a/package.json b/package.json index 1d772ab..ab4def7 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "react-map-gl": "^7.0.16", "react-map-gl-geocoder": "^2.2.0", "react-router-dom": "^6.3.0", - "react-scripts": "3.4.1" + "react-scripts": "3.4.1", + "styled-components": "^6.3.9" }, "scripts": { "start": "webpack server --mode development", diff --git a/src/App.js b/src/App.js index b74f1bf..3c886e5 100644 --- a/src/App.js +++ b/src/App.js @@ -19,14 +19,14 @@ const App = () => { const proposedTrails = LayerData.proposed; const landlines = LayerData.landline; - // Don't show intro modal if user navigates directly to communityTrailsProfile + // Don't show intro modal if user navigates directly to communityTrailsProfile or regionalTrailsProfile const [showIntroModal, toggleIntroModal] = useState( - location.pathname !== '/communityTrailsProfile' + location.pathname !== '/communityTrailsProfile' && location.pathname !== '/regionalTrailsProfile' ); // Update intro modal visibility when path changes useEffect(() => { - if (location.pathname === '/communityTrailsProfile' && showIntroModal) { + if ((location.pathname === '/communityTrailsProfile' || location.pathname === '/regionalTrailsProfile') && showIntroModal) { toggleIntroModal(false); } }, [location.pathname]); @@ -52,8 +52,8 @@ const App = () => { const [municipalityTrails, setMunicipalityTrails] = useState([]); const [showMunicipalityView, setShowMunicipalityView] = useState(false); const [showMunicipalityProfileMap, setShowMunicipalityProfileMap] = useState(false); - const [showProjectTrailsView, setShowProjectTrailsView] = useState(false); - const [showProjectTrailsProfileMap, setShowProjectTrailsProfileMap] = useState(false); + const [showRegionalTrailsView, setShowRegionalTrailsView] = useState(false); + const [showRegionalTrailsProfileMap, setShowRegionalTrailsProfileMap] = useState(false); // Layer toggle states for municipality profile const [showCommuterRail, setShowCommuterRail] = useState(false); @@ -66,10 +66,9 @@ const App = () => { const [showTrailsRegNameSync, setShowTrailsRegNameSync] = useState(false); const [showTransitLandStops, setShowTransitLandStops] = useState(false); - // Project trails profile state + // Regional trails profile state const [projectRegNames, setProjectRegNames] = useState([]); const [selectedProjectRegName, setSelectedProjectRegName] = useState(null); - const [projectColorPalette, setProjectColorPalette] = useState({}); return (
@@ -123,10 +122,10 @@ const App = () => { setShowMunicipalityView, showMunicipalityProfileMap, setShowMunicipalityProfileMap, - showProjectTrailsView, - setShowProjectTrailsView, - showProjectTrailsProfileMap, - setShowProjectTrailsProfileMap, + showRegionalTrailsView, + setShowRegionalTrailsView, + showRegionalTrailsProfileMap, + setShowRegionalTrailsProfileMap, // Layer toggle states showCommuterRail, setShowCommuterRail, @@ -150,8 +149,6 @@ const App = () => { setProjectRegNames, selectedProjectRegName, setSelectedProjectRegName, - projectColorPalette, - setProjectColorPalette, basemaps, existingTrails, proposedTrails, diff --git a/src/components/BufferAnalysisWindow/index.js b/src/components/BufferAnalysisWindow/index.js index 0ef863f..4479b29 100644 --- a/src/components/BufferAnalysisWindow/index.js +++ b/src/components/BufferAnalysisWindow/index.js @@ -303,7 +303,7 @@ const BufferAnalysisWindow = ({
-
Subway Stations
+
T-stops
{bufferResults.subwayStations ? bufferResults.subwayStations.length : 0}
@@ -522,7 +522,7 @@ const BufferAnalysisWindow = ({ className="me-2" style={{ transform: 'scale(0.8)' }} /> - MBTA Subway Stations ({bufferResults.subwayStations ? bufferResults.subwayStations.length : 0}) + T-stops ({bufferResults.subwayStations ? bufferResults.subwayStations.length : 0})
{!showSubwayStations ? ( diff --git a/src/components/ControlPanel/ProjectTrailsProfile.js b/src/components/ControlPanel/ProjectTrailsProfile.js deleted file mode 100644 index b456d4e..0000000 --- a/src/components/ControlPanel/ProjectTrailsProfile.js +++ /dev/null @@ -1,66 +0,0 @@ -import React, { useState, useEffect, useContext } from "react"; -import Form from "react-bootstrap/Form"; -import Button from "react-bootstrap/Button"; -import { LayerContext } from "../../App"; - -const ProjectTrailsProfile = ({ - regNames = [], - selectedRegNames = new Set(), - onToggleRegName -}) => { - const { basemaps } = useContext(LayerContext); - - const handleProjectToggle = (regName) => { - if (onToggleRegName) { - onToggleRegName(regName); - } - }; - - return ( -
- {/* Project List */} - {regNames.length === 0 ? ( -
-

Loading projects...

-
- ) : ( -
- {regNames.map((regName, index) => { - const isSelected = selectedRegNames.has(regName); - - return ( -
handleProjectToggle(regName)} - > - handleProjectToggle(regName)} - label={ - - {regName} - - } - style={{ cursor: 'pointer' }} - onClick={(e) => e.stopPropagation()} - /> -
- ); - })} -
- )} -
- ); -}; - -export default ProjectTrailsProfile; - diff --git a/src/components/ControlPanel/RegionalTrailsProfile.js b/src/components/ControlPanel/RegionalTrailsProfile.js new file mode 100644 index 0000000..10d5e00 --- /dev/null +++ b/src/components/ControlPanel/RegionalTrailsProfile.js @@ -0,0 +1,135 @@ +import React, { useState, useEffect, useContext, useMemo, useRef } from "react"; +import Form from "react-bootstrap/Form"; +import Button from "react-bootstrap/Button"; +import { LayerContext } from "../../App"; + +// Major trails list - these names should match grouped_reg_name values in export_major_trails FeatureServer +// Sorted alphabetically A to Z +const MAJOR_TRAILS = [ + "Bay Circuit", + "Bruce Freeman", + "Charles River Greenway", + "Minuteman", + "Neponset River", + "Northern Strand" +].sort(); + +const RegionalTrailsProfile = ({ + regNames = [], + selectedRegNames = new Set(), + onToggleRegName, + selectedMajorTrails = [], + onToggleMajorTrail +}) => { + const { basemaps } = useContext(LayerContext); + + // Check if a major trail is selected (check selectedMajorTrails array) + const isMajorTrailSelected = (majorTrail) => { + return selectedMajorTrails.includes(majorTrail); + }; + + const handleProjectToggle = (regName) => { + if (onToggleRegName) { + onToggleRegName(regName); + } + }; + + const handleMajorTrailToggle = (majorTrail) => { + if (onToggleMajorTrail) { + // Use the major trail toggle handler - directly queries export_major_trails FeatureServer + onToggleMajorTrail(majorTrail); + } + }; + + return ( +
+ {regNames.length === 0 ? ( +
+

Loading projects...

+
+ ) : ( + <> + {/* Major Trails Projects List */} +
+ Major regional trails +
+ {MAJOR_TRAILS.map((majorTrail) => { + const isSelected = isMajorTrailSelected(majorTrail); + + return ( +
handleMajorTrailToggle(majorTrail)} + > + handleMajorTrailToggle(majorTrail)} + label={ + + {majorTrail} + + } + style={{ cursor: 'pointer' }} + onClick={(e) => e.stopPropagation()} + /> +
+ ); + })} +
+
+ + {/* Other Trails Project List */} + {regNames.length > 0 && ( +
+ Other regional trails +
+ {regNames.map((regName, index) => { + const isSelected = selectedRegNames.has(regName); + + return ( +
handleProjectToggle(regName)} + > + handleProjectToggle(regName)} + label={ + + {regName} + + } + style={{ cursor: 'pointer' }} + onClick={(e) => e.stopPropagation()} + /> +
+ ); + })} +
+
+ )} + + )} +
+ ); +}; + +export default RegionalTrailsProfile; diff --git a/src/components/ControlPanel/index.js b/src/components/ControlPanel/index.js index b6e7c3a..8467d77 100644 --- a/src/components/ControlPanel/index.js +++ b/src/components/ControlPanel/index.js @@ -4,14 +4,16 @@ import Button from "react-bootstrap/Button"; import TypeButton from "./TypeButton"; import Legend from "./Legend"; import MunicipalityProfile from "./MunicipalityProfile"; -import ProjectTrailsProfile from "./ProjectTrailsProfile"; +import RegionalTrailsProfile from "./RegionalTrailsProfile"; import { ModalContext } from "../../App"; import { LayerContext } from "../../App"; import { useNavigate, useLocation } from "react-router-dom"; const ControlPanel = ({ selectedRegNames = null, - onToggleRegName = null + onToggleRegName = null, + selectedMajorTrails = [], + onToggleMajorTrail = null }) => { const navigate = useNavigate(); const location = useLocation(); @@ -38,16 +40,14 @@ const ControlPanel = ({ setShowMunicipalityView, showMunicipalityProfileMap, setShowMunicipalityProfileMap, - showProjectTrailsView, - setShowProjectTrailsView, - showProjectTrailsProfileMap, - setShowProjectTrailsProfileMap, + showRegionalTrailsView, + setShowRegionalTrailsView, + showRegionalTrailsProfileMap, + setShowRegionalTrailsProfileMap, projectRegNames, setProjectRegNames, selectedProjectRegName, setSelectedProjectRegName, - projectColorPalette, - setProjectColorPalette, // Layer toggle states from context showCommuterRail, setShowCommuterRail, @@ -95,37 +95,70 @@ const ControlPanel = ({ if ((sharedView === 'municipality' || currentPath === '/communityTrailsProfile') && !showMunicipalityView) { // Automatically switch to municipality view - setSavedTrailLayers([...trailLayers]); - setSavedProposedLayers([...proposedLayers]); - setTrailLayers([]); - setProposedLayers([]); + // Only save trail layers if we're coming from the original map view (not from another profile) + if (!showRegionalTrailsView) { + setSavedTrailLayers([...trailLayers]); + setSavedProposedLayers([...proposedLayers]); + setTrailLayers([]); + setProposedLayers([]); + } if (showMaHouseDistricts) toggleMaHouseDistricts(false); if (showMaSenateDistricts) toggleMaSenateDistricts(false); if (showMunicipalities) toggleMunicipalities(false); + // Hide all map layers by default when switching profiles + setShowCommuterRail(false); + setShowStationLabels(false); + setShowBlueBikeStations(false); + setShowSubwayStations(false); + setShowEnvironmentalJustice(false); + setShowOpenSpace(false); + setShowLandlinesFeatureService(false); + setShowTrailsRegNameSync(false); + setShowTransitLandStops(false); setShowMunicipalityProfileMap(true); setSelectedMunicipality(null); setShowMunicipalityView(true); - } else if (currentPath === '/projectTrailsProfile' && !showProjectTrailsView) { - // Automatically switch to project trails view - setSavedTrailLayers([...trailLayers]); - setSavedProposedLayers([...proposedLayers]); - setTrailLayers([]); - setProposedLayers([]); + // Disable regional trails profile when switching to community profile + setShowRegionalTrailsProfileMap(false); + setShowRegionalTrailsView(false); + } else if (currentPath === '/regionalTrailsProfile' && !showRegionalTrailsView) { + // Automatically switch to regional trails view + // Only save trail layers if we're coming from the original map view (not from another profile) + if (!showMunicipalityView) { + setSavedTrailLayers([...trailLayers]); + setSavedProposedLayers([...proposedLayers]); + setTrailLayers([]); + setProposedLayers([]); + } if (showMaHouseDistricts) toggleMaHouseDistricts(false); if (showMaSenateDistricts) toggleMaSenateDistricts(false); - // Always turn off municipalities in project trails profile + // Always turn off municipalities in regional trails profile toggleMunicipalities(false); - setShowProjectTrailsProfileMap(true); - setShowProjectTrailsView(true); - } else if (currentPath !== '/communityTrailsProfile' && currentPath !== '/projectTrailsProfile' && (showMunicipalityView || showProjectTrailsView)) { + // Hide all map layers by default when switching profiles + setShowCommuterRail(false); + setShowStationLabels(false); + setShowBlueBikeStations(false); + setShowSubwayStations(false); + setShowEnvironmentalJustice(false); + setShowOpenSpace(false); + setShowLandlinesFeatureService(false); + setShowTrailsRegNameSync(false); + setShowTransitLandStops(false); + setShowRegionalTrailsProfileMap(true); + setShowRegionalTrailsView(true); + // Disable community profile when switching to regional profile + setShowMunicipalityProfileMap(false); + setShowMunicipalityView(false); + setSelectedMunicipality(null); + } else if (currentPath !== '/communityTrailsProfile' && currentPath !== '/regionalTrailsProfile' && (showMunicipalityView || showRegionalTrailsView)) { // If we're not on a profile path but a view is active, switch back setTrailLayers(savedTrailLayers); setProposedLayers(savedProposedLayers); setShowMunicipalityProfileMap(false); - setShowProjectTrailsProfileMap(false); + setShowRegionalTrailsProfileMap(false); setSelectedMunicipality(null); setShowMunicipalityView(false); - setShowProjectTrailsView(false); + setShowRegionalTrailsView(false); setShowCommuterRail(false); setShowStationLabels(false); setShowBlueBikeStations(false); @@ -135,6 +168,11 @@ const ControlPanel = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [location.pathname]); + // Close OpenSpace layer when switching between profiles (Community ↔ Regional ↔ Trail filters) + useEffect(() => { + setShowOpenSpace(false); + }, [showMunicipalityProfileMap, showRegionalTrailsProfileMap, setShowOpenSpace]); + // Handle view toggle - show municipality profile map, hide trails const handleViewToggle = () => { if (!showMunicipalityView) { @@ -239,10 +277,51 @@ const ControlPanel = ({ } }, [selectedMunicipality, municipalityTrails, showMunicipalityView]); - // Handle project trails view toggle - const handleProjectTrailsToggle = () => { - if (!showProjectTrailsView) { - // Switching TO project trails view + // Handle switch from Regional to Community Trails Profile (close EJ and OpenSpace by default) + const handleSwitchToCommunityProfile = () => { + isNavigatingRef.current = true; + setShowEnvironmentalJustice(false); + setShowOpenSpace(false); + setShowCommuterRail(false); + setShowStationLabels(false); + setShowBlueBikeStations(false); + setShowSubwayStations(false); + setShowLandlinesFeatureService(false); + setShowTrailsRegNameSync(false); + setShowTransitLandStops(false); + setShowRegionalTrailsProfileMap(false); + setShowRegionalTrailsView(false); + setShowMunicipalityProfileMap(true); + setShowMunicipalityView(true); + setSelectedMunicipality(null); + navigate('/communityTrailsProfile'); + }; + + // Handle switch from Community to Regional Trails Profile (close EJ and OpenSpace by default) + const handleSwitchToRegionalProfile = () => { + isNavigatingRef.current = true; + setShowEnvironmentalJustice(false); + setShowOpenSpace(false); + setShowCommuterRail(false); + setShowStationLabels(false); + setShowBlueBikeStations(false); + setShowSubwayStations(false); + setShowLandlinesFeatureService(false); + setShowTrailsRegNameSync(false); + setShowTransitLandStops(false); + toggleMunicipalities(false); + setShowMunicipalityProfileMap(false); + setShowMunicipalityView(false); + setSelectedMunicipality(null); + setShowRegionalTrailsProfileMap(true); + setShowRegionalTrailsView(true); + navigate('/regionalTrailsProfile'); + }; + + // Handle regional trails view toggle + const handleRegionalTrailsToggle = () => { + if (!showRegionalTrailsView) { + // Switching TO regional trails view isNavigatingRef.current = true; // Save current trail layers @@ -256,15 +335,15 @@ const ControlPanel = ({ // Turn off other district layers if (showMaHouseDistricts) toggleMaHouseDistricts(false); if (showMaSenateDistricts) toggleMaSenateDistricts(false); - // Always turn off municipalities in project trails profile + // Always turn off municipalities in regional trails profile toggleMunicipalities(false); - // Enable the project trails profile map - setShowProjectTrailsProfileMap(true); - setShowProjectTrailsView(true); + // Enable the regional trails profile map + setShowRegionalTrailsProfileMap(true); + setShowRegionalTrailsView(true); - // Navigate to /projectTrailsProfile - navigate('/projectTrailsProfile'); + // Navigate to /regionalTrailsProfile + navigate('/regionalTrailsProfile'); } else { // Switching BACK to trail filters isNavigatingRef.current = true; @@ -273,9 +352,9 @@ const ControlPanel = ({ setTrailLayers(savedTrailLayers); setProposedLayers(savedProposedLayers); - // Disable the project trails profile map - setShowProjectTrailsProfileMap(false); - setShowProjectTrailsView(false); + // Disable the regional trails profile map + setShowRegionalTrailsProfileMap(false); + setShowRegionalTrailsView(false); // Navigate back to root path navigate('/'); @@ -283,20 +362,33 @@ const ControlPanel = ({ }; return ( -
+
- {showProjectTrailsView ? ( + {showRegionalTrailsView ? ( <> - Project Trails Profile + Regional Trails Profile + {/* Map Layers Section */}
@@ -342,17 +434,30 @@ const ControlPanel = ({ + ) : ( Find the trails that work for you! )} - {!showProjectTrailsView && !showMunicipalityView && ( + {!showRegionalTrailsView && !showMunicipalityView && (
)} - {showProjectTrailsView ? ( + {showRegionalTrailsView ? (
- {})} + selectedMajorTrails={selectedMajorTrails || []} + onToggleMajorTrail={onToggleMajorTrail || (() => {})} />
) : !showMunicipalityView ? ( diff --git a/src/components/Map/CommunityIdentify.js b/src/components/Map/CommunityIdentify.js deleted file mode 100644 index bf2c540..0000000 --- a/src/components/Map/CommunityIdentify.js +++ /dev/null @@ -1,160 +0,0 @@ -import React, { useContext, useState } from "react"; -import { Popup } from "react-map-gl"; -import Button from "react-bootstrap/Button"; -import Carousel from "react-bootstrap/Carousel"; -import editIcon from "../../assets/icons/edit-icon.svg"; -import { ModalContext } from "../../App"; -import muniKeys from "../../data/ma_muni_keys.json"; - -// Identify popup variant for Community Trails Profile: -// trail name logic matches TrailListWindow: local_name -> reg_name -> prop_name, -// treating "", "Null", " ", and "0" as missing. -const CommunityIdentify = ({ point, identifyResult, handleShowPopup, handleCarousel }) => { - const { toggleEditModal } = useContext(ModalContext); - const [carouselIndex, setCarouselIndex] = useState(0); - - const getMunicipalityName = (muniId) => { - if (!muniId || muniId === "Null" || muniId === "") return ""; - const municipality = muniKeys.find( - (muni) => - muni.muni_id === parseInt(muniId) || - muni.muni_id === muniId || - muni.muni_id.toString() === muniId.toString() - ); - return municipality ? municipality.muni_name : ""; - }; - - const normalizeCandidate = (value) => { - const v = (value ?? "").toString().trim(); - const lowered = v.toLowerCase(); - // Treat common null-ish values as missing - if ( - v === "" || - v === "0" || - lowered === "null" || - lowered === "" || - lowered === "(null)" || - lowered === "n/a" - ) { - return ""; - } - return v; - }; - - const identifyLayer = []; - const identifyTrailName = []; - const identifyMunicipality = []; - const identifyDate = []; - const identifyLength = []; - - identifyResult.forEach((element) => { - identifyLayer.push(element.layerName); - - const attrs = element.attributes || {}; - - // Handle different layer types - let name = ""; - if (element.layerId === 'transit-land-stop' || element.layerName === 'Transit Stop') { - // For transit stops, use Stop Name - name = normalizeCandidate(attrs["Stop Name"] || attrs["stop_name"] || attrs["name"]); - } else if (element.layerId === 'subway-station' || element.layerName === 'MBTA Subway Station') { - // For subway stations, use name field - name = normalizeCandidate(attrs["name"]); - } else if (element.layerId === 'blue-bike-station' || element.layerName === 'Blue Bike Station') { - // For blue bike stations, use name field - name = normalizeCandidate(attrs["name"]); - } else { - // For trails, use the standard trail name logic - const localName = normalizeCandidate(attrs["local_name"]); - const regionalName = normalizeCandidate(attrs["reg_name"]); - const propertyName = normalizeCandidate(attrs["prop_name"]); - name = localName || regionalName || propertyName || ""; - } - - identifyTrailName.push(name); - - identifyMunicipality.push(getMunicipalityName(attrs["muni_id"])); - identifyDate.push(attrs["open_date"] !== "Null" ? attrs["open_date"] : ""); - - const rawLengthFeet = attrs["length_ft"]; - const normalizedLengthFeet = - rawLengthFeet !== undefined && rawLengthFeet !== null && rawLengthFeet !== "Null" && rawLengthFeet !== " " - ? rawLengthFeet - : ""; - identifyLength.push(normalizedLengthFeet); - }); - - // Check if any result is a transit stop - const isTransitStop = identifyResult.some(result => - result.layerId === 'transit-land-stop' || result.layerName === 'Transit Stop' - ); - - const carouselItems = []; - for (let i = 0; i < identifyResult.length; i++) { - const itemIsTransitStop = identifyResult[i].layerId === 'transit-land-stop' || identifyResult[i].layerName === 'Transit Stop'; - - carouselItems.push( - - {(identifyTrailName[i] && Name: {identifyTrailName[i]}) || - (!identifyTrailName[i] && Name: N/A)} - {!itemIsTransitStop && ( - <> - {(identifyLayer[i] && ( - - Type:{" "} - {identifyLayer[i].split(" ")[0] !== "Existing" - ? identifyLayer[i] - : identifyLayer[i].split(" ").slice(1, identifyLayer[i].split(" ").length).join(" ")} - - )) || - (!identifyLayer[i] && Type: N/A)} - {(identifyMunicipality[i] && ( - Municipality: {identifyMunicipality[i]} - )) || - (!identifyMunicipality[i] && Municipality: N/A)} - {(identifyDate[i] && Opening Date: {identifyDate[i]}) || - (!identifyDate[i] && Opening Date: N/A)} - {(identifyLength[i] && ( - Length: {parseFloat(identifyLength[i]).toFixed(2)} ft - )) || (!identifyLength[i] && Length: N/A)} - - )} - - ); - } - - function handleSelect(event) { - setCarouselIndex(event); - handleCarousel(event); - } - - return ( - handleShowPopup(false)}> - 1} - activeIndex={carouselIndex} - onSelect={handleSelect} - > - {carouselItems} - - {/* Hide edit button for transit stops */} - {!isTransitStop && ( - - )} - - ); -}; - -export default CommunityIdentify; - - diff --git a/src/components/Map/CommunityTrailsProfile.js b/src/components/Map/CommunityTrailsProfile.js index 6aa8fed..2afb504 100644 --- a/src/components/Map/CommunityTrailsProfile.js +++ b/src/components/Map/CommunityTrailsProfile.js @@ -1,7 +1,6 @@ import React, { useState, useRef, useEffect, useContext } from "react"; import { useNavigate, useLocation } from "react-router-dom"; import ReactMapGL, { NavigationControl, GeolocateControl, Source, Layer, ScaleControl, Popup } from "react-map-gl"; -import axios from "axios"; import bbox from "@turf/bbox"; import * as turf from "@turf/turf"; import LoadingBar from "../LoadingBar"; @@ -10,14 +9,17 @@ import Control from "./Control"; import ControlPanel from "../ControlPanel"; import FilterIcon from "../../assets/icons/filter-icon.svg"; import GeocoderPanel from "../Geocoder/GeocoderPanel"; -import CommunityIdentify from "./CommunityIdentify"; +import CommunityIdentify from "./tooltip/CommunityIdentify"; +import EnvironmentalJusticePopupContent from "./tooltip/EnvironmentalJusticePopupContent"; +import OpenSpacePopupContent from "./tooltip/OpenSpacePopupContent"; +import BlueBikeStationPopupContent from "./tooltip/BlueBikeStationPopupContent"; import TrailLegend from "./TrailLegend"; import BufferAnalysisWindow from "../BufferAnalysisWindow"; import { LayerContext } from "../../App"; import massachusettsData from "../../data/massachusetts.json"; -import { geojsonTrailLayers } from "./constants/geojsonTrailLayers"; -import { DEFAULT_BUFFER_RADIUS } from "./constants/mapConstants"; +import { trailsProfileLayers, EJ2020_MAP_SERVER_URL } from "./constants/mapConstants"; import { queryMunicipalityTrails } from "./utils/trailQueries"; +import { queryFeatureAtPoint } from "./utils/arcgisPointQuery"; import { calculateBufferAnalysis } from "./utils/bufferAnalysis"; import CommunityTrailsProfileLayers from "./layers/CommunityTrailsProfileLayers"; import MunicipalityMapLayer from "./layers/MunicipalityMapLayer"; @@ -27,12 +29,13 @@ import BlueBikeStationsLayers from "./layers/BlueBikeStationsLayers"; import EnvironmentalJusticeLayer from "./layers/EnvironmentalJusticeLayer"; import OpenSpaceLayer from "./layers/OpenSpaceLayer"; import LandlinesLayer from "./layers/LandlinesLayer"; -import TrailsRegNameSyncLayer from "./layers/TrailsRegNameSyncLayer"; +import OtherRegionalTrailsLayer from "./layers/OtherRegionalTrailsLayer"; import TransitLandStopsLayer from "./layers/TransitLandStopsLayer"; import TransitLandRoutesLayer from "./layers/TransitLandRoutesLayer"; import { renderBufferCircle, renderBufferPreview, renderBufferCenter } from "./layers/BufferLayers"; const MAPBOX_TOKEN = process.env.REACT_APP_MAPBOX_API_TOKEN; +const DEFAULT_BUFFER_RADIUS = 1609; // 1 mile in meters const CommunityTrailsProfile = ({ viewport, @@ -52,6 +55,7 @@ const CommunityTrailsProfile = ({ municipalityTrails, setMunicipalityTrails, showMunicipalityView, + showMunicipalityProfileMap, showCommuterRail, setShowCommuterRail, showStationLabels, @@ -62,8 +66,8 @@ const CommunityTrailsProfile = ({ setShowSubwayStations, showEnvironmentalJustice, setShowEnvironmentalJustice, - showOpenSpace, - setShowOpenSpace, + showOpenSpace: showOpenSpaceCommunity, + setShowOpenSpace: setShowOpenSpaceCommunity, showLandlinesFeatureService, setShowLandlinesFeatureService, showTrailsRegNameSync, @@ -78,7 +82,6 @@ const CommunityTrailsProfile = ({ const [pointIndex, setPointIndex] = useState(0); const [isQueryingTrails, setIsQueryingTrails] = useState(false); const lastQueriedMunicipality = useRef(null); - const [selectedTrailFromList, setSelectedTrailFromList] = useState(null); const [highlightedTrail, setHighlightedTrail] = useState(null); const [loadingProgress, setLoadingProgress] = useState(0); const [loadingMessage, setLoadingMessage] = useState(""); @@ -88,30 +91,64 @@ const CommunityTrailsProfile = ({ const [hoveredCommuterRailStation, setHoveredCommuterRailStation] = useState(null); const [hoveredSubwayStation, setHoveredSubwayStation] = useState(null); const [hoveredTransitStop, setHoveredTransitStop] = useState(null); - const [ejHoverPoint, setEjHoverPoint] = useState(null); - const [ejHoverInfo, setEjHoverInfo] = useState(null); - const ejIdentifyTimeoutRef = useRef(null); + const [transitStopClickInfo, setTransitStopClickInfo] = useState(null); // Store Transit Stop click info for popup + const [blueBikeClickInfo, setBlueBikeClickInfo] = useState(null); // Store Blue Bike Station click info for popup + const [isHoveringGeometry, setIsHoveringGeometry] = useState(false); - // OpenSpace hover state - const [openSpaceHoverInfo, setOpenSpaceHoverInfo] = useState(null); + // Use global OpenSpace state instead of local state to persist across profile switches + const showOpenSpace = showOpenSpaceCommunity; + // When Community profile mounts (e.g. switching from Regional), close EJ and OpenSpace by default + const hasMountedRef = useRef(false); + useEffect(() => { + if (!hasMountedRef.current) { + hasMountedRef.current = true; + setShowEnvironmentalJustice(false); + setShowOpenSpaceCommunity(false); + } + }, []); + // OpenSpace click state const [openSpaceClickInfo, setOpenSpaceClickInfo] = useState(null); + const [environmentalJusticeClickInfo, setEnvironmentalJusticeClickInfo] = useState(null); - // Handle OpenSpace hover - const handleOpenSpaceHover = (hoverInfo) => { - setOpenSpaceHoverInfo(hoverInfo); - }; + const queryEnvironmentalJusticeAtPoint = (lng, lat) => + queryFeatureAtPoint(`${EJ2020_MAP_SERVER_URL}/0`, lng, lat); + + // Listen for OpenSpace toggle events (only for Community Trails Profile) + useEffect(() => { + const handleToggleOpenSpace = (event) => { + if (showMunicipalityProfileMap) { + setShowOpenSpaceCommunity(event.detail.show); + // Zoom to level 11 when OpenSpace is opened, only if current zoom is smaller than 11 + if (event.detail.show && mapRef?.current) { + const map = mapRef.current.getMap(); + if (map && map.getZoom() < 11) { + map.easeTo({ + zoom: 11, + duration: 1000 + }); + } + } + } + }; + + window.addEventListener('toggleOpenSpace', handleToggleOpenSpace); + return () => { + window.removeEventListener('toggleOpenSpace', handleToggleOpenSpace); + }; + }, [showMunicipalityProfileMap, setShowOpenSpaceCommunity, mapRef]); // Trail type visibility state - default all visible const [visibleTrailTypes, setVisibleTrailTypes] = useState(() => { // Initialize all trail types as visible by default const initialVisibility = {}; - geojsonTrailLayers.forEach(layer => { + trailsProfileLayers.forEach(layer => { initialVisibility[layer.id] = true; }); return initialVisibility; }); + // Fetched data states const [commuterRailData, setCommuterRailData] = useState(null); @@ -130,7 +167,6 @@ const CommunityTrailsProfile = ({ // Wrapper for queryMunicipalityTrails const handleQueryMunicipalityTrails = async (municipality) => { if (isQueryingTrails) { - console.log("Query already in progress, skipping..."); return; } @@ -201,7 +237,7 @@ const CommunityTrailsProfile = ({ const handleToggleBlueBikeStations = (event) => setShowBlueBikeStations(event.detail.show); const handleToggleSubwayStations = (event) => setShowSubwayStations(event.detail.show); const handleToggleEnvironmentalJustice = (event) => setShowEnvironmentalJustice(event.detail.show); - const handleToggleOpenSpace = (event) => setShowOpenSpace(event.detail.show); + const handleToggleOpenSpace = (event) => setShowOpenSpaceCommunity(event.detail.show); const handleToggleLandlinesFeatureService = (event) => setShowLandlinesFeatureService(event.detail.show); const handleToggleTrailsRegNameSync = (event) => setShowTrailsRegNameSync(event.detail.show); const handleToggleTransitLandStops = (event) => setShowTransitLandStops(event.detail.show); @@ -214,7 +250,7 @@ const CommunityTrailsProfile = ({ setShowBlueBikeStations(false); setShowSubwayStations(false); setShowEnvironmentalJustice(false); - setShowOpenSpace(false); + setShowOpenSpaceCommunity(false); setShowLandlinesFeatureService(false); setShowTrailsRegNameSync(false); setShowTransitLandStops(false); @@ -225,7 +261,7 @@ const CommunityTrailsProfile = ({ setBufferPreviewCenter(null); // Reset trail type visibility to all visible const resetVisibility = {}; - geojsonTrailLayers.forEach(layer => { + trailsProfileLayers.forEach(layer => { resetVisibility[layer.id] = true; }); setVisibleTrailTypes(resetVisibility); @@ -347,7 +383,7 @@ const CommunityTrailsProfile = ({ {...viewport} width="100%" height="100%" - cursor={isBufferActive ? "crosshair" : "default"} + cursor={isBufferActive ? "crosshair" : (isHoveringGeometry ? "pointer" : "default")} transformRequest={(url, resourceType) => { // Use transformRequest to add API key header for Transit.land tiles // This is recommended by Transit.land documentation @@ -364,15 +400,25 @@ const CommunityTrailsProfile = ({ return { url }; }} interactiveLayerIds={[ - ...(showOpenSpace ? ['openspace-layer', 'openspace-outline'] : []), + ...(showOpenSpace ? ['openspace-layer-community', 'openspace-outline-community'] : []), ...(showTransitLandStops ? ['transit-land-stops'] : []), + ...(showBlueBikeStations ? ['blue-bike-stations'] : []), + ...(showSubwayStations ? ['subway-stations'] : []), + ...(showCommuterRail ? ['commuter-rail-stations', 'commuter-rail-station-labels'] : []), "municipality-profile-base", - ...geojsonTrailLayers.map(layer => `geojson-trail-${layer.id}`) + ...trailsProfileLayers.map(layer => `geojson-trail-${layer.id}`) ]} onMove={(event) => { setViewport(event.viewState); }} onClick={(event) => { + const map = mapRef.current?.getMap(); + const queryPointFeatures = (layerIds) => { + if (!map || !event.lngLat) return []; + const point = [event.lngLat.lng, event.lngLat.lat]; + return map.queryRenderedFeatures(point, { layers: layerIds }); + }; + // Handle buffer creation if (isBufferActive && event.lngLat) { const center = { lng: event.lngLat.lng, lat: event.lngLat.lat }; @@ -384,203 +430,126 @@ const CommunityTrailsProfile = ({ return; } - if (event.features) { - // Check for GeoJSON trail clicks - const trailFeatures = event.features.filter((f) => + let allResults = []; + if (event.features && event.lngLat) { + + // Collect all features from event.features + const eventFeatures = event.features || []; + + // Collect GeoJSON trail features + const trailFeatures = eventFeatures.filter((f) => f.layer && f.layer.id.startsWith("geojson-trail-") ); - if (trailFeatures.length > 0) { - const trailResults = []; + trailFeatures.forEach(trailFeature => { + const layerId = trailFeature.layer.id.replace("geojson-trail-", ""); + const clickedObjectId = trailFeature.properties?.objectid || trailFeature.properties?.OBJECTID; - trailFeatures.forEach(trailFeature => { - const layerId = trailFeature.layer.id.replace("geojson-trail-", ""); - const clickedObjectId = trailFeature.properties?.objectid || trailFeature.properties?.OBJECTID; - - const trailData = intersectedTrails.find(trail => { - const trailObjectId = trail.attributes?.objectid || trail.attributes?.OBJECTID; - return trail.layerId === parseInt(layerId) && trailObjectId === clickedObjectId; - }); - - if (trailData) { - trailResults.push({ - layerId: trailData.layerId, - layerName: trailData.layerName, - attributes: trailData.attributes - }); - } + const trailData = intersectedTrails.find(trail => { + const trailObjectId = trail.attributes?.objectid || trail.attributes?.OBJECTID; + return trail.layerId === parseInt(layerId) && trailObjectId === clickedObjectId; }); - if (trailResults.length > 0) { - const firstTrail = trailResults[0]; - const firstTrailData = intersectedTrails.find(trail => { - const trailObjectId = trail.attributes?.objectid || trail.attributes?.OBJECTID; - return trail.layerId === firstTrail.layerId && - trailObjectId === (firstTrail.attributes?.objectid || firstTrail.attributes?.OBJECTID); + if (trailData) { + allResults.push({ + layerId: trailData.layerId, + layerName: trailData.layerName, + attributes: trailData.attributes }); + } + }); + + + // Collect ALL Transit Stop features + if (showTransitLandStops) { + let transitStopFeatures = eventFeatures.filter((f) => + f.layer && f.layer.id === "transit-land-stops" + ); + // Add all transit stops to results + transitStopFeatures && transitStopFeatures.forEach(feature => { + const props = feature.properties || {}; - if (firstTrailData) { - setHighlightedTrail(firstTrailData); - } + const stopName = props.stop_name - let popupCoords = null; - if (event.lngLat && !isNaN(event.lngLat.lng) && !isNaN(event.lngLat.lat)) { - popupCoords = { lng: event.lngLat.lng, lat: event.lngLat.lat }; - } else if (firstTrailData && firstTrailData.geometry && firstTrailData.geometry.coordinates) { - const coords = firstTrailData.geometry.coordinates; - const coordsArray = firstTrailData.geometry.type === 'MultiLineString' ? coords[0] : coords; - if (coordsArray && coordsArray.length > 0) { - const midPoint = coordsArray[Math.floor(coordsArray.length / 2)]; - if (midPoint && midPoint.length >= 2) { - popupCoords = { lng: midPoint[0], lat: midPoint[1] }; - } + allResults.push({ + layerId: 'transit-land-stop', + layerName: 'Transit Stop', + attributes: { + 'Stop Name': stopName } - } - - if (popupCoords) { - toggleIdentifyPopup(false); - setTimeout(() => { - setIdentifyPoint(popupCoords); - setIdentifyInfo(trailResults); - setPointIndex(0); - toggleIdentifyPopup(true); - }, 10); - } - return; - } + }); + }); } - // Check for Blue Bike Station clicks - const bikeStationFeature = event.features.find((f) => - f.layer && f.layer.id === "blue-bike-stations" - ); - if (bikeStationFeature) { - const stationProps = bikeStationFeature.properties; - const stationInfo = { - name: stationProps?.Name || 'Unknown Station', - district: stationProps?.District || 'Unknown District', - totalDocks: stationProps?.Total_docks || 0, - number: stationProps?.Number || 'N/A', - public: stationProps?.Public_ === 'Yes' ? 'Yes' : 'No' - }; + // Collect ALL Blue Bike Station features + if (showBlueBikeStations) { + let blueBikeFeatures = eventFeatures.filter((f) => + f.layer && f.layer.id === "blue-bike-stations" + ); - const mockResult = { - layerId: 'blue-bike-station', - layerName: 'Blue Bike Station', - attributes: stationInfo - }; + const queriedBlueBikes = queryPointFeatures(['blue-bike-stations']); - if (event.lngLat && !isNaN(event.lngLat.lng) && !isNaN(event.lngLat.lat)) { - toggleIdentifyPopup(false); - setTimeout(() => { - setIdentifyPoint({ lng: event.lngLat.lng, lat: event.lngLat.lat }); - setIdentifyInfo([mockResult]); - setPointIndex(0); - toggleIdentifyPopup(true); - }, 10); - } - return; + queriedBlueBikes.forEach(queriedFeature => { + const exists = blueBikeFeatures.some(existing => { + const existingId = existing.id || existing.properties?.Name || existing.properties?.Number; + const newId = queriedFeature.id || queriedFeature.properties?.Name || queriedFeature.properties?.Number; + return existingId && newId && existingId === newId; + }); + if (!exists) { + blueBikeFeatures.push(queriedFeature); + } + }); + + blueBikeFeatures.forEach(feature => { + const props = feature.properties || {}; + allResults.push({ + layerId: 'blue-bike-station', + layerName: 'Blue Bike Station', + attributes: { + name: props.Name, + District: props.District, + 'Total Docks': props.Total_docks + } + }); + }); } - - // Check for Subway Station clicks - const subwayStationFeature = event.features.find((f) => + + // Collect ALL Subway Station features + const subwayStationFeatures = eventFeatures.filter((f) => f.layer && f.layer.id === "subway-stations" ); - if (subwayStationFeature) { - const stationProps = subwayStationFeature.properties; - const stationInfo = { - name: stationProps?.STATION || 'Unknown Station', - line: stationProps?.LINE || 'Unknown Line' - }; - - const mockResult = { + subwayStationFeatures.forEach(feature => { + const props = feature.properties || {}; + allResults.push({ layerId: 'subway-station', - layerName: 'MBTA Subway Station', - attributes: stationInfo - }; - - if (event.lngLat && !isNaN(event.lngLat.lng) && !isNaN(event.lngLat.lat)) { - toggleIdentifyPopup(false); - setTimeout(() => { - setIdentifyPoint({ lng: event.lngLat.lng, lat: event.lngLat.lat }); - setIdentifyInfo([mockResult]); - setPointIndex(0); - toggleIdentifyPopup(true); - }, 10); - } - return; - } - - // Check for Transit.land stops clicks - if (showTransitLandStops) { - let transitStopFeature = event.features?.find((f) => - f.layer && f.layer.id === "transit-land-stops" - ); - - // If not found in event.features, query the map directly - if (!transitStopFeature && event.lngLat) { - const map = mapRef.current?.getMap(); - if (map) { - const point = [event.lngLat.lng, event.lngLat.lat]; - const queriedFeatures = map.queryRenderedFeatures(point, { - layers: ['transit-land-stops'] - }); - if (queriedFeatures.length > 0) { - transitStopFeature = queriedFeatures[0]; - } + layerName: 'T-stop', + attributes: { + name: props.STATION, + line: props.LINE } - } - - if (transitStopFeature && event.lngLat) { - const stopProps = transitStopFeature.properties || {}; - const stopName = stopProps?.stop_name || stopProps?.name || 'Unknown Stop'; - // Only show stop name in tooltip - const stopInfo = { - 'Stop Name': stopName - }; - - const mockResult = { - layerId: 'transit-land-stop', - layerName: 'Transit Stop', - attributes: stopInfo - }; - - if (event.lngLat && !isNaN(event.lngLat.lng) && !isNaN(event.lngLat.lat)) { - toggleIdentifyPopup(false); - setTimeout(() => { - setIdentifyPoint({ lng: event.lngLat.lng, lat: event.lngLat.lat }); - setIdentifyInfo([mockResult]); - setPointIndex(0); - toggleIdentifyPopup(true); - }, 10); - } - return; - } - } + }); + }); - // Check for OpenSpace clicks + + // Collect OpenSpace features if (showOpenSpace) { - const openSpaceFeature = event.features.find((f) => - f.layer && (f.layer.id === 'openspace-layer' || f.layer.id === 'openspace-outline') + const openSpaceFeatures = eventFeatures.filter((f) => + f.layer && (f.layer.id === 'openspace-layer-community' || f.layer.id === 'openspace-outline-community') ); - - if (openSpaceFeature && event.lngLat) { - // If clicking on the same OpenSpace feature, close the popup - if (openSpaceClickInfo && - openSpaceClickInfo.feature.properties?.OBJECTID === openSpaceFeature.properties?.OBJECTID) { - setOpenSpaceClickInfo(null); - } else { - setOpenSpaceClickInfo({ - point: { lng: event.lngLat.lng, lat: event.lngLat.lat }, - feature: openSpaceFeature - }); - } - return; - } + openSpaceFeatures.forEach(feature => { + const props = feature.properties || {}; + allResults.push({ + layerId: 'openspace', + layerName: 'OpenSpace', + attributes: { + 'name': props.SITE_NAME + } + }); + }); } - // Check for municipality clicks - const muniFeature = event.features.find((f) => f.layer && f.layer.id === "municipality-profile-base"); + // Collect Municipality features (but handle separately for navigation) + const muniFeature = eventFeatures.find((f) => f.layer && f.layer.id === "municipality-profile-base"); if (muniFeature) { const townName = muniFeature.properties.town || muniFeature.properties.NAME; if (townName) { @@ -593,28 +562,115 @@ const CommunityTrailsProfile = ({ if (showMunicipalityView && location.pathname === '/communityTrailsProfile') { navigate(`/communityTrailsProfile?muni=${encodeURIComponent(muniName)}`, { replace: true }); } - return; } } + + // If we have any results, show them all in the identify popup + if (allResults.length > 0) { + // Clear other tooltips + toggleIdentifyPopup(false); + setOpenSpaceClickInfo(null); + setTransitStopClickInfo(null); + setBlueBikeClickInfo(null); + setEnvironmentalJusticeClickInfo(null); + + // Highlight first trail if available + const firstTrailResult = allResults.find(r => r.layerId && typeof r.layerId === 'number'); + if (firstTrailResult) { + const firstTrailData = intersectedTrails.find(trail => { + const trailObjectId = trail.attributes?.objectid || trail.attributes?.OBJECTID; + return trail.layerId === firstTrailResult.layerId && + trailObjectId === (firstTrailResult.attributes?.objectid || firstTrailResult.attributes?.OBJECTID); + }); + if (firstTrailData) { + setHighlightedTrail(firstTrailData); + } + } + + let popupCoords = null; + if (event.lngLat && !isNaN(event.lngLat.lng) && !isNaN(event.lngLat.lat)) { + popupCoords = { lng: event.lngLat.lng, lat: event.lngLat.lat }; + } + + if (popupCoords) { + setTimeout(() => { + setIdentifyPoint(popupCoords); + setIdentifyInfo(allResults); + setPointIndex(0); + toggleIdentifyPopup(true); + }, 10); + } + return; + } + } + + // Check for Environmental Justice click when no vector features were clicked (EJ is raster) + if (showEnvironmentalJustice && allResults.length === 0 && event.lngLat) { + queryEnvironmentalJusticeAtPoint(event.lngLat.lng, event.lngLat.lat).then((ejFeature) => { + if (ejFeature) { + setEnvironmentalJusticeClickInfo((prev) => { + if (prev && prev.feature?.properties?.OBJECTID === ejFeature.properties?.OBJECTID) { + return null; + } + return { point: { lng: event.lngLat.lng, lat: event.lngLat.lat }, feature: ejFeature }; + }); + toggleIdentifyPopup(false); + setOpenSpaceClickInfo(null); + setTransitStopClickInfo(null); + setBlueBikeClickInfo(null); + } else { + setEnvironmentalJusticeClickInfo(null); + } + }); } // If clicking on empty space (not on any feature), close popups if (showOpenSpace && openSpaceClickInfo) { const map = mapRef.current?.getMap(); if (map && event.lngLat) { + const point = [event.lngLat.lng, event.lngLat.lat]; + const queriedFeatures = map.queryRenderedFeatures(point, { + layers: ['openspace-layer-community', 'openspace-outline-community'] + }); + if (queriedFeatures.length === 0) { + setOpenSpaceClickInfo(null); + } + } + } + + // Clear transit stop tooltip when clicking on empty space + if (showTransitLandStops && transitStopClickInfo && event.lngLat) { + const map = mapRef.current?.getMap(); + if (map) { const point = [event.lngLat.lng, event.lngLat.lat]; const queriedFeatures = map.queryRenderedFeatures(point, { - layers: ['openspace-layer', 'openspace-outline'] + layers: ['transit-land-stops'] }); if (queriedFeatures.length === 0) { - setOpenSpaceClickInfo(null); + setTransitStopClickInfo(null); + } + } + } + + // Clear blue bike station tooltip when clicking on empty space + if (showBlueBikeStations && event.features > 0) { + const map = mapRef.current?.getMap(); + if (map) { + const point = [event.lngLat.lng, event.lngLat.lat]; + const queriedFeatures = map.queryRenderedFeatures(point, { + layers: ['blue-bike-stations'] + }); + if (queriedFeatures.length === 0) { + setBlueBikeClickInfo(null); } } } - // If clicking on empty space and no features found, close identify popup + + // If clicking on empty space and no features found, close identify popup and EJ popup if (!event.features || event.features.length === 0) { toggleIdentifyPopup(false); + setEnvironmentalJusticeClickInfo(null); } }} onMouseMove={(event) => { @@ -627,55 +683,45 @@ const CommunityTrailsProfile = ({ setBufferPreviewCenter(null); } - // Handle OpenSpace layer hover FIRST (before other features) - if (showOpenSpace && event.lngLat) { - const map = mapRef.current?.getMap(); - if (map) { - // First check event.features - const openSpaceFeature = features.find(f => - f.layer && (f.layer.id === 'openspace-layer' || f.layer.id === 'openspace-outline') - ); - - if (openSpaceFeature) { - setOpenSpaceHoverInfo({ - point: event.lngLat, - feature: openSpaceFeature - }); - } else { - // If not in event.features, query the map directly - const queriedFeatures = map.queryRenderedFeatures(event.point, { - layers: ['openspace-layer', 'openspace-outline'] - }); - if (queriedFeatures.length > 0) { - const feature = queriedFeatures.find(f => f.layer.id === 'openspace-layer') || queriedFeatures[0]; - setOpenSpaceHoverInfo({ - point: event.lngLat, - feature: feature - }); - } else { - setOpenSpaceHoverInfo(null); - } - } - } - } else { - setOpenSpaceHoverInfo(null); + // Check if hovering over any interactive geometry + let hasInteractiveFeature = false; + + if (features.length > 0) { + hasInteractiveFeature = features.some((f) => { + if (!f.layer) return false; + const layerId = f.layer.id; + // Check for trails + if (layerId.startsWith("geojson-trail-") && !layerId.includes("hover")) return true; + // Check for OpenSpace + if (showOpenSpace && (layerId === "openspace-layer-community" || layerId === "openspace-outline-community")) return true; + // Check for TransitLand routes + if (showTransitLandStops && layerId === "transit-land-routes") return true; + // Check for TransitLand stops + if (showTransitLandStops && layerId === "transit-land-stops") return true; + // Check for municipality + if (layerId === "municipality-profile-base") return true; + // Check for Blue Bike Stations + if (showBlueBikeStations && layerId === "blue-bike-stations") return true; + // Check for Subway Stations + if (showSubwayStations && layerId === "subway-stations") return true; + // Check for Commuter Rail Stations + if (showCommuterRail && (layerId === "commuter-rail-stations" || layerId === "commuter-rail-station-labels")) return true; + return false; + }); } + + setIsHoveringGeometry(hasInteractiveFeature); // Handle trail hover if (features.length > 0) { - const trailFeature = features.find((f) => - f.layer && f.layer.id.startsWith("geojson-trail-") && !f.layer.id.includes("hover") - ); - + const trailFeature = features.find((f) => f.layer && f.layer.id.startsWith("geojson-trail-") && !f.layer.id.includes("hover")); if (trailFeature) { const layerId = trailFeature.layer.id.replace("geojson-trail-", ""); const clickedObjectId = trailFeature.properties?.objectid || trailFeature.properties?.OBJECTID; - - const trailData = intersectedTrails.find(trail => { + const trailData = intersectedTrails.find((trail) => { const trailObjectId = trail.attributes?.objectid || trail.attributes?.OBJECTID; return trail.layerId === parseInt(layerId) && trailObjectId === clickedObjectId; }); - if (trailData) { setHoveredTrail(trailData); } else { @@ -719,62 +765,9 @@ const CommunityTrailsProfile = ({ setHoveredBlueBikeStation(null); setHoveredSubwayStation(null); setHoveredTransitStop(null); + setIsHoveringGeometry(false); } - // Handle Environmental Justice layer hover - // Note: Raster layers don't appear in features, so we query identify endpoint when layer is visible - if (showEnvironmentalJustice && event.lngLat) { - setEjHoverPoint(event.lngLat); - - // Debounce identify requests to avoid too many API calls - if (ejIdentifyTimeoutRef.current) { - clearTimeout(ejIdentifyTimeoutRef.current); - } - - ejIdentifyTimeoutRef.current = setTimeout(() => { - const EJ2020_IDENTIFY_URL = "https://arcgisserver.digital.mass.gov/arcgisserver/rest/services/AGOL/EJ2020/MapServer/identify"; - const map = mapRef.current?.getMap(); - - if (map) { - const mapBounds = map.getBounds(); - const sw = mapBounds.getSouthWest(); - const ne = mapBounds.getNorthEast(); - - axios - .get(EJ2020_IDENTIFY_URL, { - params: { - geometry: `${event.lngLat.lng},${event.lngLat.lat}`, - geometryType: "esriGeometryPoint", - sr: 4326, - layers: "all:0", - tolerance: 5, - mapExtent: `${sw.lng},${sw.lat},${ne.lng},${ne.lat}`, - imageDisplay: `${map.getContainer().clientWidth || 1024},${map.getContainer().clientHeight || 768},96`, - returnGeometry: false, - f: "pjson", - }, - }) - .then((res) => { - if (res.data.results && res.data.results.length > 0) { - setEjHoverInfo(res.data.results[0]); - } else { - setEjHoverInfo(null); - } - }) - .catch((error) => { - console.error("Error identifying EJ feature:", error); - setEjHoverInfo(null); - }); - } - }, 200); - } else { - // Clear EJ hover when layer is not visible - setEjHoverPoint(null); - setEjHoverInfo(null); - if (ejIdentifyTimeoutRef.current) { - clearTimeout(ejIdentifyTimeoutRef.current); - } - } }} onMouseLeave={() => { // Clear all hover states when mouse leaves the map @@ -782,12 +775,7 @@ const CommunityTrailsProfile = ({ setHoveredBlueBikeStation(null); setHoveredSubwayStation(null); setHoveredTransitStop(null); - setOpenSpaceHoverInfo(null); - setEjHoverPoint(null); - setEjHoverInfo(null); - if (ejIdentifyTimeoutRef.current) { - clearTimeout(ejIdentifyTimeoutRef.current); - } + setIsHoveringGeometry(false); }} mapboxAccessToken={MAPBOX_TOKEN} mapStyle={baseLayer.url} @@ -801,135 +789,82 @@ const CommunityTrailsProfile = ({ handleShowPopup={() => { toggleIdentifyPopup(false); setHighlightedTrail(null); - setSelectedTrailFromList(null); }} handleCarousel={setPointIndex} /> )} - {/* Environmental Justice Tooltip */} - {showEnvironmentalJustice && ejHoverPoint && ejHoverInfo && ( + {/* Environmental Justice Click Popup */} + {showEnvironmentalJustice && environmentalJusticeClickInfo?.point && environmentalJusticeClickInfo?.feature && ( setEnvironmentalJusticeClickInfo(null)} anchor="top" offset={12} > - {(() => { - const attributes = ejHoverInfo.attributes || {}; - const layerName = ejHoverInfo.layerName || "Environmental Justice"; - - // Extract relevant EJ attributes - const geographicAreaName = attributes["Geographic Area Name"] || attributes.Geographic_Area_Name || null; - const totalHouseholds = attributes["Total Number of Households"] || attributes.Total_Number_of_Households || null; - const totalPopulation = attributes["Total Poputation"] || attributes.Total_Poputation || attributes["Total Population"] || attributes.Total_Population || null; - - return ( -
-
{layerName}
- {geographicAreaName && ( -
{geographicAreaName}
- )} - {totalHouseholds !== null && ( -
Total Number of Households: {totalHouseholds}
- )} - {totalPopulation !== null && ( -
Total Population: {totalPopulation}
- )} - {!geographicAreaName && !totalHouseholds && totalPopulation === null && ( -
No data available
- )} -
- ); - })()} +
)} - {/* OpenSpace Hover Tooltip */} - {showOpenSpace && openSpaceHoverInfo && openSpaceHoverInfo.point && openSpaceHoverInfo.feature && !openSpaceClickInfo && ( + {/* OpenSpace Click Popup */} + {showOpenSpace && openSpaceClickInfo?.point && openSpaceClickInfo?.feature && ( setOpenSpaceClickInfo(null)} anchor="top" offset={12} > - {(() => { - const properties = openSpaceHoverInfo.feature.properties || {}; - - return ( -
-
OpenSpace
- {properties.SITE_NAME && ( -
{properties.SITE_NAME}
- )} - {properties.FEE_OWNER && ( -
Owner: {properties.FEE_OWNER}
- )} - {properties.OWNER_TYPE && ( -
Owner Type: {properties.OWNER_TYPE}
- )} - {properties.PRIM_PURP && ( -
Primary Purpose: {properties.PRIM_PURP}
- )} - {properties.PUB_ACCESS && ( -
Public Access: {properties.PUB_ACCESS}
- )} - {properties.GIS_ACRES !== null && properties.GIS_ACRES !== undefined && ( -
Acres: {parseFloat(properties.GIS_ACRES).toFixed(2)}
- )} - {!properties.SITE_NAME && !properties.FEE_OWNER && ( -
No data available
- )} -
- ); - })()} +
)} - - {/* OpenSpace Click Popup */} - {showOpenSpace && openSpaceClickInfo && openSpaceClickInfo.point && openSpaceClickInfo.feature && ( + + {/* Transit Stop Click Popup */} + {(() => { + const shouldShowPopup = showTransitLandStops && transitStopClickInfo && transitStopClickInfo.point && transitStopClickInfo.feature; + + return shouldShowPopup ? ( + { + setTransitStopClickInfo(null); + }} + anchor="top" + offset={12} + > + {(() => { + const properties = transitStopClickInfo.feature.properties || {}; + const allProps = { ...properties }; + + const stopName = allProps.stop_name; + + return ( +
+
Transit Stop
+
{stopName}
+
+ ); + })()} +
+ ) : null; + })()} + + {/* Blue Bike Station Click Popup */} + {showBlueBikeStations && blueBikeClickInfo?.point && blueBikeClickInfo?.feature && ( setOpenSpaceClickInfo(null)} + onClose={() => setBlueBikeClickInfo(null)} anchor="top" offset={12} > - {(() => { - const properties = openSpaceClickInfo.feature.properties || {}; - - return ( -
-
OpenSpace
- {properties.SITE_NAME && ( -
{properties.SITE_NAME}
- )} - {properties.FEE_OWNER && ( -
Owner: {properties.FEE_OWNER}
- )} - {properties.OWNER_TYPE && ( -
Owner Type: {properties.OWNER_TYPE}
- )} - {properties.PRIM_PURP && ( -
Primary Purpose: {properties.PRIM_PURP}
- )} - {properties.PUB_ACCESS && ( -
Public Access: {properties.PUB_ACCESS}
- )} - {properties.GIS_ACRES !== null && properties.GIS_ACRES !== undefined && ( -
Acres: {parseFloat(properties.GIS_ACRES).toFixed(2)}
- )} - {!properties.SITE_NAME && !properties.FEE_OWNER && ( -
No data available
- )} -
- ); - })()} +
)} @@ -988,6 +923,7 @@ const CommunityTrailsProfile = ({ )} @@ -1003,10 +939,10 @@ const CommunityTrailsProfile = ({ {/* Trails Reg Name Sync Layer */} {showTrailsRegNameSync && ( - )} diff --git a/src/components/Map/OriginalTrailsMap.js b/src/components/Map/OriginalTrailsMap.js index bc1a134..03a538e 100644 --- a/src/components/Map/OriginalTrailsMap.js +++ b/src/components/Map/OriginalTrailsMap.js @@ -10,7 +10,7 @@ import MAhouseDistrictsButton from '../MAhouseDistrictsButton'; import MASenateDistrictsButton from '../MASenateDistrictsButton'; import MunicipalitiesButton from '../MunicipalitiesButton'; import GeocoderPanel from "../Geocoder/GeocoderPanel"; -import Identify from "./Identify"; +import Identify from "./tooltip/Identify"; import { LayerContext } from "../../App"; import massachusettsData from "../../data/massachusetts.json"; import OriginalTrailsFilterLayers from "./layers/OriginalTrailsFilterLayers"; @@ -49,20 +49,21 @@ const OriginalTrailsMap = ({ const [identifyInfo, setIdentifyInfo] = useState(null); const [identifyPoint, setIdentifyPoint] = useState(null); const [pointIndex, setPointIndex] = useState(0); - const [hoverPoint, setHoverPoint] = useState(null); - const [hoverFeature, setHoverFeature] = useState(null); - const [hoverFilterKey, setHoverFilterKey] = useState(null); - const [hoverFilterValue, setHoverFilterValue] = useState(null); - const [senateHoverPoint, setSenateHoverPoint] = useState(null); - const [senateHoverFeature, setSenateHoverFeature] = useState(null); - const [senateHoverFilterKey, setSenateHoverFilterKey] = useState(null); - const [senateHoverFilterValue, setSenateHoverFilterValue] = useState(null); - const [muniHoverPoint, setMuniHoverPoint] = useState(null); - const [muniHoverFeature, setMuniHoverFeature] = useState(null); - const [muniHoverFilterKey, setMuniHoverFilterKey] = useState(null); - const [muniHoverFilterValue, setMuniHoverFilterValue] = useState(null); + const [clickHousePoint, setClickHousePoint] = useState(null); + const [clickHouseFeature, setClickHouseFeature] = useState(null); + const [clickHouseFilterKey, setClickHouseFilterKey] = useState(null); + const [clickHouseFilterValue, setClickHouseFilterValue] = useState(null); + const [clickSenatePoint, setClickSenatePoint] = useState(null); + const [clickSenateFeature, setClickSenateFeature] = useState(null); + const [clickSenateFilterKey, setClickSenateFilterKey] = useState(null); + const [clickSenateFilterValue, setClickSenateFilterValue] = useState(null); + const [clickMuniPoint, setClickMuniPoint] = useState(null); + const [clickMuniFeature, setClickMuniFeature] = useState(null); + const [clickMuniFilterKey, setClickMuniFilterKey] = useState(null); + const [clickMuniFilterValue, setClickMuniFilterValue] = useState(null); const [showOneLayerNotice, setShowOneLayerNotice] = useState(false); const [isZooming, setIsZooming] = useState(false); + const hoveredTrailRef = React.useRef(null); // Show notice when any one of the exclusive layers turns on React.useEffect(() => { @@ -82,39 +83,39 @@ const OriginalTrailsMap = ({ React.useEffect(() => { if (isZooming) { const timer = setTimeout(() => { - setHoverFeature(null); - setHoverPoint(null); - setHoverFilterKey(null); - setHoverFilterValue(null); - setSenateHoverFeature(null); - setSenateHoverPoint(null); - setSenateHoverFilterKey(null); - setSenateHoverFilterValue(null); - setMuniHoverFeature(null); - setMuniHoverPoint(null); - setMuniHoverFilterKey(null); - setMuniHoverFilterValue(null); + setClickHouseFeature(null); + setClickHousePoint(null); + setClickHouseFilterKey(null); + setClickHouseFilterValue(null); + setClickSenateFeature(null); + setClickSenatePoint(null); + setClickSenateFilterKey(null); + setClickSenateFilterValue(null); + setClickMuniFeature(null); + setClickMuniPoint(null); + setClickMuniFilterKey(null); + setClickMuniFilterValue(null); setIsZooming(false); }, 1100); return () => clearTimeout(timer); } }, [isZooming]); - // Clear hover states when identify popup closes + // Clear click states when identify popup closes React.useEffect(() => { if (!showIdentifyPopup) { - setHoverFeature(null); - setHoverPoint(null); - setHoverFilterKey(null); - setHoverFilterValue(null); - setSenateHoverFeature(null); - setSenateHoverPoint(null); - setSenateHoverFilterKey(null); - setSenateHoverFilterValue(null); - setMuniHoverFeature(null); - setMuniHoverPoint(null); - setMuniHoverFilterKey(null); - setMuniHoverFilterValue(null); + setClickHouseFeature(null); + setClickHousePoint(null); + setClickHouseFilterKey(null); + setClickHouseFilterValue(null); + setClickSenateFeature(null); + setClickSenatePoint(null); + setClickSenateFilterKey(null); + setClickSenateFilterValue(null); + setClickMuniFeature(null); + setClickMuniPoint(null); + setClickMuniFilterKey(null); + setClickMuniFilterValue(null); } }, [showIdentifyPopup]); @@ -156,8 +157,8 @@ const OriginalTrailsMap = ({ ); visibleMaHouseDistrictsLayers.push( @@ -204,8 +205,8 @@ const OriginalTrailsMap = ({ ); visibleMaSenateDistrictsLayers.push( @@ -253,8 +254,8 @@ const OriginalTrailsMap = ({ visibleMunicipalitiesLayers.push( @@ -281,8 +282,58 @@ const OriginalTrailsMap = ({ interactiveLayerIds={[ "ma-house-districts-fill", "ma-senate-districts-fill", - "municipalities-fill" + "municipalities-fill", + ...trailLayers, + ...proposedLayers ]} + onMouseMove={(event) => { + const map = mapRef.current?.getMap?.(); + if (!map) return; + let features = event.features; + if (!features?.length && event.point) { + features = map.queryRenderedFeatures([event.point.x, event.point.y], { + layers: [...trailLayers, ...proposedLayers] + }); + } + const trailFeature = features?.find((f) => { + const lid = f.layer?.id; + return lid && (trailLayers.includes(lid) || proposedLayers.includes(lid)); + }); + const prev = hoveredTrailRef.current; + if (trailFeature) { + const sourceLayer = trailFeature.layer?.sourceLayer ?? trailFeature.sourceLayer; + const id = trailFeature.id ?? trailFeature.properties?.OBJECTID ?? trailFeature.properties?.objectid; + if (sourceLayer && id != null) { + if (prev && (prev.sourceLayer !== sourceLayer || prev.id !== id)) { + try { + map.removeFeatureState({ source: "MAPC trail vector tiles", sourceLayer: prev.sourceLayer, id: prev.id }); + } catch (_) {} + } + try { + map.setFeatureState( + { source: "MAPC trail vector tiles", sourceLayer, id }, + { hover: true } + ); + hoveredTrailRef.current = { sourceLayer, id }; + } catch (_) {} + } + } else if (prev) { + try { + map.removeFeatureState({ source: "MAPC trail vector tiles", sourceLayer: prev.sourceLayer, id: prev.id }); + } catch (_) {} + hoveredTrailRef.current = null; + } + }} + onMouseLeave={() => { + const map = mapRef.current?.getMap?.(); + const prev = hoveredTrailRef.current; + if (map && prev) { + try { + map.removeFeatureState({ source: "MAPC trail vector tiles", sourceLayer: prev.sourceLayer, id: prev.id }); + } catch (_) {} + hoveredTrailRef.current = null; + } + }} onMove={(event) => { const newViewport = event.viewState; if (Math.abs(newViewport.zoom - viewport.zoom) > 0.01) { @@ -291,65 +342,12 @@ const OriginalTrailsMap = ({ setViewport(newViewport); }} onClick={(event) => { - // Check if clicking on a municipality when municipalities layer is visible - if (showMunicipalities && event.features) { - const muniFeature = event.features.find((f) => f.layer && f.layer.id === "municipalities-fill"); - if (muniFeature) { - const townName = muniFeature.properties.town || muniFeature.properties.NAME; - if (townName) { - const muniName = townName.toLowerCase(); - setSelectedMunicipality({ - name: muniName, - properties: muniFeature.properties, - geometry: muniFeature.geometry - }); - return; - } - } - } - - // Handle identify popup for trails - const allLayers = [ - ...existingTrails.filter((et) => trailLayers.includes(et.id)).map((et) => et["esri-id"]), - ...proposedTrails.filter((et) => proposedLayers.includes(et.id)).map((et) => et["esri-id"]), - ].join(","); - if (trailLayers.length > 0 || proposedLayers.length > 0) { - const currentMap = mapRef.current.getMap(); - const currentMapBounds = currentMap.getBounds(); - axios - .get(TRAILMAP_IDENTIFY_SOURCE, { - params: { - geometry: `${event.lngLat.lng},${event.lngLat.lat}`, - geometryType: "esriGeometryPoint", - sr: 4326, - layers: "visible:" + allLayers, - tolerance: 3, - mapExtent: `${currentMapBounds._sw.lng},${currentMapBounds._sw.lat},${currentMapBounds._ne.lng},${currentMapBounds._ne.lat}`, - imageDisplay: `600,550,96`, - returnGeometry: false, - f: "pjson", - }, - }) - .then((res) => { - if (res.data.results.length > 0) { - const identifyResult = []; - for (let i = 0; i < Math.min(5, res.data.results.length); i++) { - identifyResult.push(res.data.results[i]); - } - setIdentifyInfo(identifyResult); - toggleIdentifyPopup(true); - setIdentifyPoint(event.lngLat); - } - }); - } - }} - onMouseMove={(event) => { const map = mapRef.current && mapRef.current.getMap ? mapRef.current.getMap() : null; - const features = event.features || []; - - // Handle MA House Districts hover + let handled = false; + + // Handle MA House Districts click if (showMaHouseDistricts) { - let districtFeature = features.find((f) => f.layer && f.layer.id === "ma-house-districts-fill"); + let districtFeature = event.features?.find((f) => f.layer && f.layer.id === "ma-house-districts-fill"); if (!districtFeature && map) { const x = event.point.x; @@ -363,8 +361,18 @@ const OriginalTrailsMap = ({ } if (districtFeature) { - setHoverFeature(districtFeature); - setHoverPoint(event.lngLat); + // Clear other click states + setClickSenateFeature(null); + setClickSenatePoint(null); + setClickSenateFilterKey(null); + setClickSenateFilterValue(null); + setClickMuniFeature(null); + setClickMuniPoint(null); + setClickMuniFilterKey(null); + setClickMuniFilterValue(null); + + setClickHouseFeature(districtFeature); + setClickHousePoint(event.lngLat); const props = districtFeature.properties || {}; const key = (props.REPDISTNUM !== undefined && "REPDISTNUM") || @@ -372,19 +380,15 @@ const OriginalTrailsMap = ({ (props.OBJECTID !== undefined && "OBJECTID") || null; const value = key ? props[key] : null; - setHoverFilterKey(key); - setHoverFilterValue(value); - } else { - setHoverFeature(null); - setHoverPoint(null); - setHoverFilterKey(null); - setHoverFilterValue(null); + setClickHouseFilterKey(key); + setClickHouseFilterValue(value); + handled = true; } } - // Handle MA Senate Districts hover - if (showMaSenateDistricts) { - let senateFeature = features.find((f) => f.layer && f.layer.id === "ma-senate-districts-fill"); + // Handle MA Senate Districts click + if (!handled && showMaSenateDistricts) { + let senateFeature = event.features?.find((f) => f.layer && f.layer.id === "ma-senate-districts-fill"); if (!senateFeature && map) { const x = event.point.x; @@ -398,72 +402,141 @@ const OriginalTrailsMap = ({ } if (senateFeature) { - setSenateHoverFeature(senateFeature); - setSenateHoverPoint(event.lngLat); + // Clear other click states + setClickHouseFeature(null); + setClickHousePoint(null); + setClickHouseFilterKey(null); + setClickHouseFilterValue(null); + setClickMuniFeature(null); + setClickMuniPoint(null); + setClickMuniFilterKey(null); + setClickMuniFilterValue(null); + + setClickSenateFeature(senateFeature); + setClickSenatePoint(event.lngLat); const props = senateFeature.properties || {}; const key = (props.DIST_CODE !== undefined && "DIST_CODE") || (props.OBJECTID !== undefined && "OBJECTID") || null; const value = key ? props[key] : null; - setSenateHoverFilterKey(key); - setSenateHoverFilterValue(value); - } else { - setSenateHoverFeature(null); - setSenateHoverPoint(null); - setSenateHoverFilterKey(null); - setSenateHoverFilterValue(null); + setClickSenateFilterKey(key); + setClickSenateFilterValue(value); + handled = true; } } - // Handle Municipalities hover - if (showMunicipalities) { - let muniFeature = features.find((f) => f.layer && f.layer.id === "municipalities-fill"); + // Check if clicking on a municipality when municipalities layer is visible + let muniFeature = null; + if (!handled && showMunicipalities) { + muniFeature = event.features?.find((f) => f.layer && f.layer.id === "municipalities-fill"); if (!muniFeature && map) { const x = event.point.x; const y = event.point.y; - const queried = map.queryRenderedFeatures([[x - 8, y - 8], [x + 8, y + 8]], { - layers: ["municipalities-fill"], - }); - if (queried && queried.length > 0) { - muniFeature = queried[0]; + // Try point query first (most reliable), then larger bbox for edge cases + const pointQuery = map.queryRenderedFeatures([x, y], { layers: ["municipalities-fill"] }); + if (pointQuery && pointQuery.length > 0) { + muniFeature = pointQuery[0]; + } else { + const queried = map.queryRenderedFeatures([[x - 16, y - 16], [x + 16, y + 16]], { + layers: ["municipalities-fill"], + }); + if (queried && queried.length > 0) { + muniFeature = queried[0]; + } } } if (muniFeature) { - setMuniHoverFeature(muniFeature); - setMuniHoverPoint(event.lngLat); - const props = muniFeature.properties || {}; - const key = - (props.town !== undefined && "town") || - (props.NAME !== undefined && "NAME") || - (props.OBJECTID !== undefined && "OBJECTID") || - null; - const value = key ? props[key] : null; - setMuniHoverFilterKey(key); - setMuniHoverFilterValue(value); - } else { - setMuniHoverFeature(null); - setMuniHoverPoint(null); - setMuniHoverFilterKey(null); - setMuniHoverFilterValue(null); + const townName = muniFeature.properties.town || muniFeature.properties.NAME; + if (townName) { + const muniName = townName.toLowerCase(); + setSelectedMunicipality({ + name: muniName, + properties: muniFeature.properties, + geometry: muniFeature.geometry + }); + + // Clear other click states + setClickHouseFeature(null); + setClickHousePoint(null); + setClickHouseFilterKey(null); + setClickHouseFilterValue(null); + setClickSenateFeature(null); + setClickSenatePoint(null); + setClickSenateFilterKey(null); + setClickSenateFilterValue(null); + + // Also show click tooltip + setClickMuniFeature(muniFeature); + setClickMuniPoint(event.lngLat); + const props = muniFeature.properties || {}; + const key = + (props.town !== undefined && "town") || + (props.NAME !== undefined && "NAME") || + (props.OBJECTID !== undefined && "OBJECTID") || + null; + const value = key ? props[key] : null; + setClickMuniFilterKey(key); + setClickMuniFilterValue(value); + handled = true; + } + } + } + + // If none of the above layers were clicked, clear all click states + if (!handled) { + setClickHouseFeature(null); + setClickHousePoint(null); + setClickHouseFilterKey(null); + setClickHouseFilterValue(null); + setClickSenateFeature(null); + setClickSenatePoint(null); + setClickSenateFilterKey(null); + setClickSenateFilterValue(null); + setClickMuniFeature(null); + setClickMuniPoint(null); + setClickMuniFilterKey(null); + setClickMuniFilterValue(null); + } + + // Handle identify popup for trails (only when NOT clicking on municipality) + if (!muniFeature) { + const allLayers = [ + ...existingTrails.filter((et) => trailLayers.includes(et.id)).map((et) => et["esri-id"]), + ...proposedTrails.filter((et) => proposedLayers.includes(et.id)).map((et) => et["esri-id"]), + ].join(","); + if ((trailLayers.length > 0 || proposedLayers.length > 0) && allLayers) { + const currentMap = mapRef.current.getMap(); + const currentMapBounds = currentMap.getBounds(); + axios + .get(TRAILMAP_IDENTIFY_SOURCE, { + params: { + geometry: `${event.lngLat.lng},${event.lngLat.lat}`, + geometryType: "esriGeometryPoint", + sr: 4326, + layers: "visible:" + allLayers, + tolerance: 5, + mapExtent: `${currentMapBounds._sw.lng},${currentMapBounds._sw.lat},${currentMapBounds._ne.lng},${currentMapBounds._ne.lat}`, + imageDisplay: `600,550,96`, + returnGeometry: false, + f: "pjson", + }, + }) + .then((res) => { + if (res.data.results && res.data.results.length > 0) { + const identifyResult = []; + for (let i = 0; i < Math.min(5, res.data.results.length); i++) { + identifyResult.push(res.data.results[i]); + } + setIdentifyInfo(identifyResult); + toggleIdentifyPopup(true); + setIdentifyPoint(event.lngLat); + } + }); } } - }} - onMouseLeave={() => { - setHoverFeature(null); - setHoverPoint(null); - setHoverFilterKey(null); - setHoverFilterValue(null); - setSenateHoverFeature(null); - setSenateHoverPoint(null); - setSenateHoverFilterKey(null); - setSenateHoverFilterValue(null); - setMuniHoverFeature(null); - setMuniHoverPoint(null); - setMuniHoverFilterKey(null); - setMuniHoverFilterValue(null); }} mapboxAccessToken={MAPBOX_TOKEN} mapStyle={baseLayer.url} @@ -476,18 +549,18 @@ const OriginalTrailsMap = ({ identifyResult={identifyInfo} handleShowPopup={() => { toggleIdentifyPopup(false); - setHoverFeature(null); - setHoverPoint(null); - setHoverFilterKey(null); - setHoverFilterValue(null); - setSenateHoverFeature(null); - setSenateHoverPoint(null); - setSenateHoverFilterKey(null); - setSenateHoverFilterValue(null); - setMuniHoverFeature(null); - setMuniHoverPoint(null); - setMuniHoverFilterKey(null); - setMuniHoverFilterValue(null); + setClickHouseFeature(null); + setClickHousePoint(null); + setClickHouseFilterKey(null); + setClickHouseFilterValue(null); + setClickSenateFeature(null); + setClickSenatePoint(null); + setClickSenateFilterKey(null); + setClickSenateFilterValue(null); + setClickMuniFeature(null); + setClickMuniPoint(null); + setClickMuniFilterKey(null); + setClickMuniFilterValue(null); }} handleCarousel={setPointIndex} /> @@ -501,16 +574,6 @@ const OriginalTrailsMap = ({ {showBasemapPanel && } - {/* Render vector tile source for original trails filters */} - - - - {landlineLayers()} @@ -555,6 +618,16 @@ const OriginalTrailsMap = ({ {municipalitiesLayers()} + {/* Trail segments rendered last so they stay on top */} + + + + toggleBasemapPanel(!showBasemapPanel)} /> - {showMaHouseDistricts && hoverFeature && hoverPoint && ( + {showMaHouseDistricts && clickHouseFeature && clickHousePoint && ( {(() => { - const p = hoverFeature.properties || {}; + const p = clickHouseFeature.properties || {}; const repName = p.REP || ""; const distName = p.REP_DIST || ""; const distNum = p.DIST_CODE || ""; @@ -596,17 +668,16 @@ const OriginalTrailsMap = ({ )} - {showMaSenateDistricts && senateHoverFeature && senateHoverPoint && ( + {showMaSenateDistricts && clickSenateFeature && clickSenatePoint && ( {(() => { - const p = senateHoverFeature.properties || {}; + const p = clickSenateFeature.properties || {}; const repName = p.SENATOR || ""; const distName = p.SEN_DIST || ""; const distNum = p.SENDISTNUM || ""; @@ -621,25 +692,30 @@ const OriginalTrailsMap = ({ )} - {showMunicipalities && muniHoverFeature && muniHoverPoint && ( + {showMunicipalities && clickMuniFeature && clickMuniPoint && ( { + setClickMuniFeature(null); + setClickMuniPoint(null); + setClickMuniFilterKey(null); + setClickMuniFilterValue(null); + }} anchor="top" offset={12} + closeOnClick={false} > - {(() => { - const p = muniHoverFeature.properties || {}; - const townName = p.town || "N/A"; - const capitalizedTownName = townName && townName !== "N/A" ? townName.charAt(0).toUpperCase() + townName.slice(1).toLowerCase() : townName; - return ( -
- {capitalizedTownName &&
Municipality: {capitalizedTownName}
} -
- ); - })()} +
+ Municipality:{" "} + {(() => { + const p = clickMuniFeature.properties || {}; + const townName = p.town || p.NAME || ""; + return townName ? townName.charAt(0).toUpperCase() + townName.slice(1).toLowerCase() : "Unknown"; + })()} +
)} diff --git a/src/components/Map/ProjectMetricsPanel.js b/src/components/Map/ProjectMetricsPanel.js index 3327151..2c6f22b 100644 --- a/src/components/Map/ProjectMetricsPanel.js +++ b/src/components/Map/ProjectMetricsPanel.js @@ -1,129 +1,671 @@ -import React from "react"; +import React, { useState } from "react"; const ProjectMetricsPanel = ({ selectedRegNames = new Set(), - projectMetrics = {} + selectedMajorTrails = [], + projectMetrics = {}, + onZoomToProject = null, + allTrailsData = null, + majorTrailsData = null }) => { - // Reverse order so newest selected projects appear at the top - const selectedProjectsMetrics = Array.from(selectedRegNames) - .map(regName => ({ - regName, - metrics: projectMetrics[regName] - })) + const [expandedProjects, setExpandedProjects] = useState(new Set()); + const [isPanelVisible, setIsPanelVisible] = useState(true); + const [expandedLengthByType, setExpandedLengthByType] = useState(new Map()); // Map of projectName -> { existing: true/false, planned: true/false, gap: true/false } + + // Combine regular projects and major trails, reverse order so newest selected projects appear at the top + const regularProjects = Array.from(selectedRegNames).map(regName => ({ + regName, + metrics: projectMetrics[regName] + })); + + const majorTrails = selectedMajorTrails.map(majorTrailName => ({ + regName: majorTrailName, + metrics: projectMetrics[majorTrailName] + })); + + const selectedProjectsMetrics = [...regularProjects, ...majorTrails] .filter(item => item.metrics) .reverse(); // Reverse to show newest at top + const toggleProject = (regName) => { + const newExpanded = new Set(expandedProjects); + if (newExpanded.has(regName)) { + newExpanded.delete(regName); + } else { + newExpanded.add(regName); + } + setExpandedProjects(newExpanded); + }; + + const toggleLengthByTypeSection = (regName, section) => { + const newExpanded = new Map(expandedLengthByType); + const projectState = newExpanded.get(regName) || { existing: true, planned: true, gap: true }; + projectState[section] = !projectState[section]; + newExpanded.set(regName, projectState); + setExpandedLengthByType(newExpanded); + }; + + // Download GeoJSON for a specific trail + const downloadTrailGeoJSON = (regName, e) => { + e.stopPropagation(); + + let trailFeatures = []; + + // Check if it's a major trail + const isMajorTrail = selectedMajorTrails.includes(regName); + + if (isMajorTrail && majorTrailsData && majorTrailsData.features) { + // Filter major trails by grouped_reg_name + trailFeatures = majorTrailsData.features.filter( + feature => { + const groupedRegName = (feature.properties?.grouped_reg_name || "").trim(); + return groupedRegName === regName.trim(); + } + ); + } else if (allTrailsData && allTrailsData.features) { + // Filter regular trails by reg_name + trailFeatures = allTrailsData.features.filter( + feature => (feature.properties?.reg_name || "").trim() === regName.trim() + ); + } + + if (trailFeatures.length === 0) { + alert(`No trail data available for ${regName}`); + return; + } + + // Create GeoJSON FeatureCollection + const geoJSON = { + type: "FeatureCollection", + features: trailFeatures + }; + + // Create filename from regName (sanitize for filesystem) + const sanitizedName = regName.replace(/[^a-z0-9]/gi, '_').toLowerCase(); + const filename = `${sanitizedName}_trails.geojson`; + + // Create blob and download + const blob = new Blob([JSON.stringify(geoJSON, null, 2)], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = filename; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + }; + // Render metrics for a single project const renderProjectMetrics = (projectItem, index) => { const { regName, metrics } = projectItem; + const isExpanded = expandedProjects.has(regName); return (
-
-
- {regName} -
-
- -
- {/* Municipalities */} - {metrics.municipalities && metrics.municipalities.length > 0 && ( -
- Municipalities ({metrics.municipalities.length}): -
- {metrics.municipalities.map((muni, muniIndex) => ( -
- • {muni} -
- ))} -
+ {/* Project Header - Always Visible */} +
toggleProject(regName)} + onMouseEnter={(e) => { + e.currentTarget.style.backgroundColor = '#e9ecef'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.backgroundColor = '#f8f9fa'; + }} + > +
+
+ {regName} +
+ {/* Quick Stats */} +
+ {metrics && metrics.totalLengthMiles ? ( + <> + + {metrics.totalLengthMiles} miles total + + {metrics.percentageComplete && ( + = 50 ? '#28a745' : '#ffc107' }} title="(existing trails ÷ total) × 100"> + {metrics.percentageComplete}% complete + + )} + + ) : ( + + + Loading metrics... + + )}
- )} - - {/* Total Length */} -
- Total Length: {metrics.totalLengthMiles} miles
+
+ {onZoomToProject && ( + + )} + + +
+
- {/* Completed Length */} - {metrics.completedLengthMiles && ( -
- Completed: {metrics.completedLengthMiles} miles -
- )} + {/* Expanded Content */} + {isExpanded && ( +
+ {/* Loading State */} + {!metrics || !metrics.totalLengthMiles ? ( +
+ + Loading metrics... +
+ ) : ( + <> + {/* Progress Bar */} + {metrics.percentageComplete && ( +
+
+ + + Completion Progress + + {metrics.percentageComplete}% +
+
+ (existing trails ÷ total) × 100 +
+
+
= 50 ? '#28a745' : '#ffc107', + transition: 'width 0.3s ease' + }}>
+
+
+ )} - {/* Percentage Complete */} - {metrics.percentageComplete && ( -
- Percentage Complete: {metrics.percentageComplete}% -
- )} - - {/* Length by Type */} - {metrics.lengthByType && metrics.lengthByType.length > 0 && ( -
- Length by Type: -
- {metrics.lengthByType.map((item, idx) => ( -
- • {item.type}: {item.miles} miles -
- ))} + {/* Key Metrics Grid */} +
+
+
+ {metrics.totalLengthMiles} +
+
+ + + Total Miles + + Existing + Planned + Envisioned + Design + gaps +
-
- )} - - {/* Parks */} - {metrics.parks && metrics.parks.length > 0 && ( -
- Parks ({metrics.parks.length}): -
- {metrics.parks.map((park, parkIndex) => ( -
- • {park} + {metrics.completedLengthMiles && ( +
+
+ {metrics.completedLengthMiles}
- ))} -
+
+ + + Completed Miles + + Existing trails +
+
+ )}
- )} - {/* Trail Steward */} - {metrics.steward && ( -
- Trail Steward: {metrics.steward} -
- )} - - {/* Trail Website */} - {metrics.website && ( -
- Website:{' '} - - {metrics.website} - -
- )} - - {/* Key Gaps */} - {metrics.gaps && metrics.gaps.length > 0 && ( -
- Key Gaps ({metrics.gaps.length}): -
- {metrics.gaps.map((gap, gapIndex) => ( -
- • {gap.type}: {gap.lengthMiles} miles + {/* Municipalities */} + {metrics.municipalities && metrics.municipalities.length > 0 && ( +
+
+ + Municipalities ({metrics.municipalities.length}) +
+
15 ? '120px' : 'none', + overflowY: metrics.municipalities.length > 15 ? 'auto' : 'visible', + padding: metrics.municipalities.length > 15 ? '8px' : '0', + backgroundColor: metrics.municipalities.length > 15 ? '#f8f9fa' : 'transparent', + borderRadius: '4px' + }} + > + {metrics.municipalities.map((muni, muniIndex) => ( + + {muni} + + ))} +
+
+ )} + + {/* Length by Type - Separated into Existing, Planned, and Gap */} + {metrics.lengthByType && metrics.lengthByType.length > 0 && ( +
+
+ + Length by Type +
+ + {/* Existing Trails */} + {metrics.lengthByType.filter(item => item.category === 'existing').length > 0 && (() => { + const existingItems = metrics.lengthByType.filter(item => item.category === 'existing'); + const isExpanded = expandedLengthByType.get(regName)?.existing !== false; + return ( +
+
toggleLengthByTypeSection(regName, 'existing')} + onMouseEnter={(e) => { + e.currentTarget.style.color = '#1e5a8a'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.color = '#2774bd'; + }} + > + Existing + +
+ {isExpanded && ( +
+ {existingItems.map((item, idx, filtered) => ( +
+ {item.type} + {item.miles} mi +
+ ))} +
+ )} +
+ ); + })()} + + {/* Planned Trails */} + {metrics.lengthByType.filter(item => item.category === 'planned').length > 0 && (() => { + const plannedItems = metrics.lengthByType.filter(item => item.category === 'planned'); + const isExpanded = expandedLengthByType.get(regName)?.planned !== false; + return ( +
+
toggleLengthByTypeSection(regName, 'planned')} + onMouseEnter={(e) => { + e.currentTarget.style.color = '#4a148c'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.color = '#6a1b9a'; + }} + > + Planned/Envisioned/Design + +
+ {isExpanded && ( +
+ {plannedItems.map((item, idx, filtered) => ( +
+ {item.type} + {item.miles} mi +
+ ))} +
+ )} +
+ ); + })()} + + {/* Gap Trails */} + {metrics.lengthByType.filter(item => item.category === 'gap').length > 0 && (() => { + const gapItems = metrics.lengthByType.filter(item => item.category === 'gap'); + const isExpanded = expandedLengthByType.get(regName)?.gap !== false; + return ( +
+
toggleLengthByTypeSection(regName, 'gap')} + onMouseEnter={(e) => { + e.currentTarget.style.color = '#cc0000'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.color = '#FF0000'; + }} + > + Gap + +
+ {isExpanded && ( +
+ {gapItems.map((item, idx, filtered) => ( +
+ {item.type} + {item.miles} mi +
+ ))} +
+ )} +
+ ); + })()} +
+ )} + + {/* Parks */} + {metrics.parks && metrics.parks.length > 0 && ( +
+
+ + Parks ({metrics.parks.length}) +
+
+ {metrics.parks.slice(0, 5).map((park, parkIndex) => ( +
+ • {park} +
+ ))} + {metrics.parks.length > 5 && ( +
+ + {metrics.parks.length - 5} more +
+ )} +
+
+ )} + + {/* Trail Steward & Website */} + {(metrics.steward || metrics.website) && ( + -
- )} -
+ )} + + + )} + +
+ )}
); }; @@ -134,18 +676,106 @@ const ProjectMetricsPanel = ({ } return ( -
-
-
Project Metrics
-
-
- {selectedProjectsMetrics.map((projectItem, index) => - renderProjectMetrics(projectItem, index) - )} -
+
+ {isPanelVisible ? ( + <> +
setIsPanelVisible(false)} + onMouseEnter={(e) => { + e.currentTarget.style.backgroundColor = 'rgba(39, 116, 189, 0.1)'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.backgroundColor = ''; + }} + > +
+ + Regional Trails Metrics + + ({selectedProjectsMetrics.length}) + + +
+
+
+ {selectedProjectsMetrics.map((projectItem, index) => + renderProjectMetrics(projectItem, index) + )} +
+ + ) : ( +
setIsPanelVisible(true)} + onMouseEnter={(e) => { + e.currentTarget.style.backgroundColor = 'rgba(39, 116, 189, 0.1)'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.backgroundColor = ''; + }} + > +
+ + Regional Trails Metrics + + ({selectedProjectsMetrics.length}) + + +
+
+ )}
); }; export default ProjectMetricsPanel; - diff --git a/src/components/Map/ProjectTrailsProfile.js b/src/components/Map/ProjectTrailsProfile.js deleted file mode 100644 index 1f3f560..0000000 --- a/src/components/Map/ProjectTrailsProfile.js +++ /dev/null @@ -1,766 +0,0 @@ -import React, { useState, useRef, useEffect, useContext, useMemo } from "react"; -import { useNavigate, useLocation } from "react-router-dom"; -import ReactMapGL, { NavigationControl, GeolocateControl, ScaleControl, Popup, Source, Layer } from "react-map-gl"; -import BasemapPanel from "../BasemapPanel"; -import ControlPanel from "../ControlPanel"; -import Control from "./Control"; -import FilterIcon from "../../assets/icons/filter-icon.svg"; -import CommunityIdentify from "./CommunityIdentify"; -import ProjectMetricsPanel from "./ProjectMetricsPanel"; -import GeocoderPanel from "../Geocoder/GeocoderPanel"; -import { LayerContext } from "../../App"; -import TrailsRegNameSyncLayer from "./layers/TrailsRegNameSyncLayer"; -import OpenSpaceLayer from "./layers/OpenSpaceLayer"; -import EnvironmentalJusticeLayer from "./layers/EnvironmentalJusticeLayer"; -import massachusettsData from "../../data/massachusetts.json"; -import * as turf from "@turf/turf"; -import bbox from "@turf/bbox"; - -const MAPBOX_TOKEN = process.env.REACT_APP_MAPBOX_API_TOKEN; - -const ProjectTrailsProfile = ({ - viewport, - setViewport, - baseLayer, - showBasemapPanel, - toggleBasemapPanel, - showControlPanel, - toggleControlPanel, - mapRef -}) => { - const navigate = useNavigate(); - const location = useLocation(); - const { - showTrailsRegNameSync, - setShowTrailsRegNameSync, - basemaps, - setProjectRegNames, - setSelectedProjectRegName, - setProjectColorPalette, - showMunicipalities, - toggleMunicipalities, - showOpenSpace, - setShowOpenSpace, - showEnvironmentalJustice, - setShowEnvironmentalJustice, - } = useContext(LayerContext); - - const [showIdentifyPopup, toggleIdentifyPopup] = useState(false); - const [identifyInfo, setIdentifyInfo] = useState(null); - const [identifyPoint, setIdentifyPoint] = useState(null); - const [pointIndex, setPointIndex] = useState(0); - const [regNames, setRegNames] = useState([]); - const [selectedRegNames, setSelectedRegNames] = useState(new Set()); // Track selected projects (Set for easy toggle) - - // Reset selected projects when entering Project Trails Profile and show municipalities by default - useEffect(() => { - if (location.pathname === '/projectTrailsProfile') { - setSelectedRegNames(new Set()); - // Show municipalities by default - toggleMunicipalities(true); - } - }, [location.pathname, toggleMunicipalities]); - const [hoveredTrail, setHoveredTrail] = useState(null); - const [colorPalette, setColorPalette] = useState({}); - const allRegNamesRef = useRef(new Set()); // Track all unique reg_names seen using ref - const [allTrailsData, setAllTrailsData] = useState(null); // Store all trail data from TrailsRegNameSyncLayer - const [openSpaceData, setOpenSpaceData] = useState(null); // Store OpenSpace data for park intersection calculations - const [openSpaceClickInfo, setOpenSpaceClickInfo] = useState(null); // Store OpenSpace click info for popup - - // Get trail type label based on seg_type and fac_stat - const getTrailTypeLabel = (segType, facStat) => { - const key = `${segType},${facStat}`; - const typeMap = { - "1,1": "Shared Use Path - Existing", - "1,2": "Shared Use Path - Design", - "1,3": "Shared Use Path - Envisioned", - "6,3": "Shared Use Path - Unimproved Surface", - "6,1": "Shared Use Path - Unimproved Surface", - "6,2": "Shared Use Path - Unimproved Surface", - "2,1": "Protected Bike Lane and Sidewalk", - "2,2": "Protected Bike Lane - Design or Construction", - "2,3": "Protected Bike Lane - Design or Construction", - "3,1": "Bike Lane and Sidewalk", - "3,2": "Bike Lane - Design or Construction", - "3,3": "Bike Lane - Design or Construction", - "4,3": "Shared Street - Urban", - "4,1": "Shared Street - Urban", - "5,1": "Shared Street - Suburban", - "5,3": "Shared Street - Envisioned", - "9,1": "Gap - Facility Type TBD", - "9,2": "Gap - Facility Type TBD", - "9,3": "Gap - Facility Type TBD", - "11,1": "Foot Trail - Natural Surface", - "11,3": "Foot Trail - Envisioned Natural Surface", - "11,2": "Foot Trail - Envisioned Natural Surface", - "12,1": "Foot Trail - Roadway Section", - "12,2": "Foot Trail - Envisioned Roadway Section", - "12,3": "Foot Trail - Envisioned Roadway Section" - }; - - return typeMap[key] || "Unknown Trail Type"; - }; - - // Color palette generation function - const generateColorPalette = (regNamesArray) => { - const colors = [ - "#FF6B35", "#4ECDC4", "#45B7D1", "#FFA07A", "#98D8C8", - "#F7DC6F", "#BB8FCE", "#85C1E2", "#F8B739", "#52BE80", - "#EC7063", "#5DADE2", "#F1948A", "#58D68D", "#F4D03F", - "#AF7AC5", "#7FB3D3", "#F5B041", "#82E0AA", "#F39C12", - "#E74C3C", "#3498DB", "#E67E22", "#1ABC9C", "#9B59B6", - "#34495E", "#16A085", "#27AE60", "#2980B9", "#8E44AD" - ]; - - const palette = {}; - regNamesArray.forEach((name, index) => { - if (name && name.trim() !== "") { - palette[name] = colors[index % colors.length]; - } - }); - - return palette; - }; - - // Update color palette when new reg_names are discovered - useEffect(() => { - if (regNames.length > 0) { - // Add new reg_names to the ref set - const previousSize = allRegNamesRef.current.size; - regNames.forEach(name => { - if (name && name.trim() !== "") { - allRegNamesRef.current.add(name); - } - }); - - // Only update if we have new reg_names - if (allRegNamesRef.current.size !== previousSize) { - // Generate stable color palette based on sorted reg_names - const sortedRegNames = Array.from(allRegNamesRef.current).sort(); - const palette = generateColorPalette(sortedRegNames); - - setColorPalette(palette); - if (setProjectRegNames) setProjectRegNames(sortedRegNames); - if (setProjectColorPalette) setProjectColorPalette(palette); - } else { - // Even if no new reg_names, update context with current regNames - if (setProjectRegNames) setProjectRegNames(regNames); - } - } - }, [regNames, setProjectRegNames, setProjectColorPalette]); - - // Update selected reg names in context - useEffect(() => { - if (setSelectedProjectRegName) { - // Convert Set to array for context (or pass first selected if single selection expected) - const selectedArray = Array.from(selectedRegNames); - setSelectedProjectRegName(selectedArray.length > 0 ? selectedArray[0] : null); - } - }, [selectedRegNames, setSelectedProjectRegName]); - - // Zoom to selected project trails extent - const previousSelectedRef = useRef(new Set()); - useEffect(() => { - if (!allTrailsData || !allTrailsData.features || selectedRegNames.size === 0) { - previousSelectedRef.current = new Set(selectedRegNames); - return; - } - - const map = mapRef.current?.getMap(); - if (!map) { - previousSelectedRef.current = new Set(selectedRegNames); - return; - } - - // Find newly selected projects (projects that were just added) - const newlySelected = Array.from(selectedRegNames).filter( - regName => !previousSelectedRef.current.has(regName) - ); - - // Only zoom if a new project was just selected - if (newlySelected.length > 0) { - // Get trails for the newly selected project(s) - const trailsToZoom = allTrailsData.features.filter(feature => { - const regName = (feature.properties?.reg_name || "").trim(); - return newlySelected.some(selected => selected.trim() === regName); - }); - - if (trailsToZoom.length > 0) { - try { - // Create a FeatureCollection with the trails - const featureCollection = { - type: "FeatureCollection", - features: trailsToZoom - }; - - // Calculate bounding box - const bounds = bbox(featureCollection); - - // Fit map to bounds with padding - map.fitBounds( - [ - [bounds[0], bounds[1]], // Southwest corner - [bounds[2], bounds[3]] // Northeast corner - ], - { - padding: { top: 100, bottom: 100, left: 100, right: 100 }, - duration: 1000, - maxZoom: 15 - } - ); - } catch (e) { - console.warn("Error fitting bounds to project trails:", e); - } - } - } - - // Update previous selected ref - previousSelectedRef.current = new Set(selectedRegNames); - }, [selectedRegNames, allTrailsData]); - - // Handle trail click - const handleTrailClick = async (event) => { - const map = mapRef.current?.getMap(); - if (!map || !event.lngLat) { - toggleIdentifyPopup(false); - setOpenSpaceClickInfo(null); - return; - } - - // Check for OpenSpace clicks first - if (showOpenSpace && event.features) { - const openSpaceFeature = event.features.find((f) => - f.layer && (f.layer.id === 'openspace-layer' || f.layer.id === 'openspace-outline') - ); - - if (openSpaceFeature) { - // If clicking on the same OpenSpace feature, close the popup - if (openSpaceClickInfo && - openSpaceClickInfo.feature.properties?.OBJECTID === openSpaceFeature.properties?.OBJECTID) { - setOpenSpaceClickInfo(null); - } else { - setOpenSpaceClickInfo({ - point: { lng: event.lngLat.lng, lat: event.lngLat.lat }, - feature: openSpaceFeature - }); - } - toggleIdentifyPopup(false); - return; - } - } - - let trailFeatures = []; - - // First, try to get features from event.features - if (event.features && event.features.length > 0) { - trailFeatures = event.features.filter((f) => - f.layer && (f.layer.id === "trails-reg-name-sync-layer" || f.layer.id === "gaps-reg-name-sync-layer") - ); - } - - // If no features found, query the map directly - if (trailFeatures.length === 0) { - const point = [event.lngLat.lng, event.lngLat.lat]; - // Query all rendered features at the click point - const allFeatures = map.queryRenderedFeatures(point); - - // Filter for trail layers (including gaps) - trailFeatures = allFeatures.filter((f) => - f.layer && (f.layer.id === "trails-reg-name-sync-layer" || f.layer.id === "gaps-reg-name-sync-layer") - ); - } - - if (trailFeatures.length > 0) { - const trailResults = trailFeatures.map(feature => { - const props = feature.properties || {}; - const segType = props.seg_type; - const facStat = props.fac_stat; - const trailTypeLabel = getTrailTypeLabel(segType, facStat); - - return { - layerName: trailTypeLabel, - attributes: props - }; - }); - - if (trailResults.length > 0) { - const popupCoords = { lng: event.lngLat.lng, lat: event.lngLat.lat }; - - toggleIdentifyPopup(false); - setOpenSpaceClickInfo(null); - setTimeout(() => { - setIdentifyPoint(popupCoords); - setIdentifyInfo(trailResults); - setPointIndex(0); - toggleIdentifyPopup(true); - }, 10); - } - } else { - // If clicking on empty space, close popups - toggleIdentifyPopup(false); - if (showOpenSpace) { - const point = [event.lngLat.lng, event.lngLat.lat]; - const queriedFeatures = map.queryRenderedFeatures(point, { - layers: ['openspace-layer', 'openspace-outline'] - }); - if (queriedFeatures.length === 0) { - setOpenSpaceClickInfo(null); - } - } - } - }; - - // Handle trail hover - const handleTrailHover = (event) => { - const map = mapRef.current?.getMap(); - if (!map || !event.lngLat) { - setHoveredTrail(null); - return; - } - - const point = [event.lngLat.lng, event.lngLat.lat]; - const features = event.features || map.queryRenderedFeatures(point); - - // Handle trail hover (including gaps) - const trailFeature = features.find((f) => - f.layer && (f.layer.id === "trails-reg-name-sync-layer" || f.layer.id === "gaps-reg-name-sync-layer") - ); - - if (trailFeature) { - setHoveredTrail({ - properties: trailFeature.properties, - lngLat: event.lngLat, - featureId: trailFeature.properties?.OBJECTID || - trailFeature.properties?.objectid || - trailFeature.id || - null - }); - return; - } - - // No municipality hover handling - municipalities are always visible but not interactive - setHoveredTrail(null); - }; - - // Calculate metrics for selected projects - const projectMetrics = useMemo(() => { - if (!allTrailsData || !allTrailsData.features || selectedRegNames.size === 0) { - return {}; - } - - const metrics = {}; - - // Process each selected project - Array.from(selectedRegNames).forEach(regName => { - // Filter trails for this project - const projectTrails = allTrailsData.features.filter( - feature => (feature.properties?.reg_name || "").trim() === regName.trim() - ); - - if (projectTrails.length === 0) { - metrics[regName] = { - totalLength: 0, - totalLengthMiles: 0, - municipalities: [] - }; - return; - } - - // Calculate total length and categorize by status and type - let totalLengthFeet = 0; - let completedLengthFeet = 0; // fac_stat = 1 means existing/completed - const lengthByType = {}; // Track length by trail type - const gaps = []; // Track gaps (seg_type = 9) - - projectTrails.forEach(trail => { - const props = trail.properties || {}; - const segType = props.seg_type; - const facStat = props.fac_stat; - const trailTypeLabel = getTrailTypeLabel(segType, facStat); - - // Try to get length from attributes first - const lengthAttr = props.length_ft || - props['Facility Length in Feet'] || - props.Shape_Length || - 0; - - let lengthFeet = Number(lengthAttr) || 0; - - // If no length attribute, calculate from geometry using turf - if (lengthFeet === 0 && trail.geometry) { - try { - const lengthMeters = turf.length(trail, { units: 'meters' }); - lengthFeet = lengthMeters * 3.28084; // Convert meters to feet - } catch (e) { - console.warn("Error calculating trail length:", e); - } - } - - totalLengthFeet += lengthFeet; - - // Track completed length (fac_stat = 1) - if (facStat === 1 || facStat === "1") { - completedLengthFeet += lengthFeet; - } - - // Track length by type - if (!lengthByType[trailTypeLabel]) { - lengthByType[trailTypeLabel] = 0; - } - lengthByType[trailTypeLabel] += lengthFeet; - - // Track gaps (seg_type = 9) - if (segType === 9 || segType === "9") { - gaps.push({ - type: trailTypeLabel, - length: lengthFeet, - geometry: trail.geometry - }); - } - }); - - const totalLengthMiles = totalLengthFeet / 5280; - const completedLengthMiles = completedLengthFeet / 5280; - const percentageComplete = totalLengthFeet > 0 - ? ((completedLengthFeet / totalLengthFeet) * 100).toFixed(1) - : 0; - - // Determine which municipalities the trails are in - const municipalitySet = new Set(); - - if (massachusettsData && massachusettsData.features) { - projectTrails.forEach(trail => { - if (trail.geometry) { - try { - const trailFeature = turf.feature(trail.geometry); - - massachusettsData.features.forEach(muni => { - if (muni.geometry) { - try { - const muniPolygon = turf.feature(muni.geometry); - const intersects = turf.booleanIntersects(trailFeature, muniPolygon); - - if (intersects) { - const muniName = muni.properties?.town || muni.properties?.NAME || null; - if (muniName) { - municipalitySet.add(muniName); - } - } - } catch (e) { - // Skip if geometry is invalid - } - } - }); - } catch (e) { - // Skip if trail geometry is invalid - } - } - }); - } - - // Find parks (OpenSpace) that trails pass through - const parksSet = new Set(); - if (openSpaceData && openSpaceData.features) { - projectTrails.forEach(trail => { - if (trail.geometry) { - try { - const trailFeature = turf.feature(trail.geometry); - - openSpaceData.features.forEach(park => { - if (park.geometry) { - try { - const parkPolygon = turf.feature(park.geometry); - const intersects = turf.booleanIntersects(trailFeature, parkPolygon); - - if (intersects) { - const parkName = park.properties?.SITE_NAME || - park.properties?.NAME || - park.properties?.name || - "Unnamed Park"; - parksSet.add(parkName); - } - } catch (e) { - // Skip if geometry is invalid - } - } - }); - } catch (e) { - // Skip if trail geometry is invalid - } - } - }); - } - - // Get trail steward and website from first trail (assuming they're consistent for a project) - const firstTrail = projectTrails[0]; - const steward = firstTrail?.properties?.steward || - firstTrail?.properties?.Steward || - firstTrail?.properties?.STEWARD || - null; - const website = firstTrail?.properties?.website || - firstTrail?.properties?.Website || - firstTrail?.properties?.WEBSITE || - firstTrail?.properties?.url || - firstTrail?.properties?.URL || - null; - - // Convert lengthByType to array with miles - const lengthByTypeArray = Object.entries(lengthByType).map(([type, feet]) => ({ - type, - miles: (feet / 5280).toFixed(2) - })); - - metrics[regName] = { - totalLength: totalLengthFeet, - totalLengthMiles: totalLengthMiles.toFixed(2), - completedLengthMiles: completedLengthMiles.toFixed(2), - percentageComplete: percentageComplete, - municipalities: Array.from(municipalitySet).sort(), - parks: Array.from(parksSet).sort(), - steward: steward, - website: website, - lengthByType: lengthByTypeArray, - gaps: gaps.map(gap => ({ - type: gap.type, - lengthMiles: (gap.length / 5280).toFixed(2) - })) - }; - }); - - return metrics; - }, [allTrailsData, selectedRegNames, openSpaceData]); - - - // Get all layer IDs for trails reg name sync (only selected projects) - const getTrailLayerIds = () => { - const layerIds = []; - if (selectedRegNames.size > 0) { - // Add regular trail layer - layerIds.push("trails-reg-name-sync-layer"); - // Add gap layer - layerIds.push("gaps-reg-name-sync-layer"); - } - // Add OpenSpace layers if OpenSpace is shown - if (showOpenSpace) { - layerIds.push("openspace-layer"); - layerIds.push("openspace-outline"); - } - // Don't add municipalities-fill to interactive layers since we don't want hover - return layerIds; - }; - - // Municipality layers function - always show, no hover - const municipalitiesLayers = () => { - const visibleMunicipalitiesLayers = []; - // Always show municipalities in project trails profile - visibleMunicipalitiesLayers.push( - - ); - return visibleMunicipalitiesLayers; - }; - - // Ensure baseLayer and MAPBOX_TOKEN exist before rendering - if (!baseLayer || !baseLayer.url || !MAPBOX_TOKEN) { - return null; - } - - return ( -
- { - setViewport(event.viewState); - }} - onClick={handleTrailClick} - onMouseMove={handleTrailHover} - onMouseLeave={() => { - setHoveredTrail(null); - }} - mapboxAccessToken={MAPBOX_TOKEN} - mapStyle={baseLayer.url} - scrollZoom={true} - transitionDuration="1000" - > - {/* Trails Reg Name Sync Layer */} - - - {/* Hover popup */} - {hoveredTrail && hoveredTrail.lngLat && ( - -
- {hoveredTrail.properties?.reg_name || 'Unknown Project'} -
-
- )} - - {/* Identify popup */} - {showIdentifyPopup && identifyPoint && identifyInfo && identifyInfo.length > 0 && ( - { - toggleIdentifyPopup(false); - }} - handleCarousel={setPointIndex} - /> - )} - - {/* OpenSpace Click Popup */} - {showOpenSpace && openSpaceClickInfo && openSpaceClickInfo.point && openSpaceClickInfo.feature && ( - setOpenSpaceClickInfo(null)} - anchor="top" - offset={12} - > - {(() => { - const properties = openSpaceClickInfo.feature.properties || {}; - - return ( -
-
OpenSpace
- {properties.SITE_NAME && ( -
{properties.SITE_NAME}
- )} - {properties.FEE_OWNER && ( -
Owner: {properties.FEE_OWNER}
- )} - {properties.OWNER_TYPE && ( -
Owner Type: {properties.OWNER_TYPE}
- )} - {properties.PRIM_PURP && ( -
Primary Purpose: {properties.PRIM_PURP}
- )} - {properties.PUB_ACCESS && ( -
Public Access: {properties.PUB_ACCESS}
- )} - {properties.GIS_ACRES !== null && properties.GIS_ACRES !== undefined && ( -
Acres: {parseFloat(properties.GIS_ACRES).toFixed(2)}
- )} - {!properties.SITE_NAME && !properties.FEE_OWNER && ( -
No data available
- )} -
- ); - })()} -
- )} - - {/* Municipality Map Layer - always visible */} - - {municipalitiesLayers()} - - - {/* OpenSpace Layer */} - {showOpenSpace && ( - - )} - - {/* Environmental Justice Layer */} - {showEnvironmentalJustice && ( - - )} - - {/* Geocoder - styled to appear inside control panel */} - - - {/* Map controls */} - - - - - {/* Control Panel Toggle Button */} - toggleControlPanel(!showControlPanel)} - /> -
- - - {/* Basemap Panel */} - {showBasemapPanel && ( - - )} - - {/* Control Panel */} - {showControlPanel && ( -
- { - const newSelected = new Set(selectedRegNames); - if (newSelected.has(regName)) { - newSelected.delete(regName); - } else { - newSelected.add(regName); - } - setSelectedRegNames(newSelected); - }} - /> -
- )} - - {/* Project Metrics Panel - separate window on the left */} - -
- ); -}; - -export default ProjectTrailsProfile; - diff --git a/src/components/Map/RegionalTrailsProfile.js b/src/components/Map/RegionalTrailsProfile.js new file mode 100644 index 0000000..c861824 --- /dev/null +++ b/src/components/Map/RegionalTrailsProfile.js @@ -0,0 +1,998 @@ +import React, { useState, useRef, useEffect, useContext, useMemo } from "react"; +import { useNavigate, useLocation } from "react-router-dom"; +import ReactMapGL, { NavigationControl, GeolocateControl, ScaleControl, Popup, Source, Layer } from "react-map-gl"; +import BasemapPanel from "../BasemapPanel"; +import ControlPanel from "../ControlPanel"; +import Control from "./Control"; +import FilterIcon from "../../assets/icons/filter-icon.svg"; +import CommunityIdentify from "./tooltip/CommunityIdentify"; +import ProjectMetricsPanel from "./ProjectMetricsPanel"; +import GeocoderPanel from "../Geocoder/GeocoderPanel"; +import { LayerContext } from "../../App"; +import OtherRegionalTrailsLayer from "./layers/OtherRegionalTrailsLayer"; +import MajorTrailsLayer from "./layers/MajorTrailsLayer"; +import OpenSpaceLayer from "./layers/OpenSpaceLayer"; +import EnvironmentalJusticeLayer from "./layers/EnvironmentalJusticeLayer"; +import EnvironmentalJusticePopupContent from "./tooltip/EnvironmentalJusticePopupContent"; +import OpenSpacePopupContent from "./tooltip/OpenSpacePopupContent"; +import TrailPopupContent from "./tooltip/TrailPopupContent"; +import massachusettsData from "../../data/massachusetts.json"; +import { getMunicipalityName } from "./utils/municipalityUtils"; +import { queryFeatureAtPoint } from "./utils/arcgisPointQuery"; +import { getFeaturesAtPoint } from "./utils/mapQueryUtils"; +import { TRAIL_FACILITY_TYPE_LABELS, EJ2020_MAP_SERVER_URL } from "./constants/mapConstants"; +import bbox from "@turf/bbox"; +import styled from "styled-components"; + +// Trail Status Legend +const TrailStatusLegend = styled.div` + position: absolute; + bottom: 40px; + right: 10px; + background: rgba(255, 255, 255, 0.95); + border: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); + border-radius: 6px; + padding: 12px; + z-index: 1000; + font-size: 12px; + min-width: 180px; +`; + +const TrailStatusLegendHeader = styled.div` + margin-bottom: 8px; + padding-bottom: 6px; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + font-weight: 600; + font-size: 13px; + color: #333; +`; + +const TrailStatusLegendList = styled.div` + display: flex; + flex-direction: column; + gap: 8px; +`; + +const TrailStatusLegendItem = styled.div` + display: flex; + align-items: center; + gap: 8px; +`; + +const TrailStatusLegendSwatch = styled.div` + width: 30px; + height: 3px; + background-color: ${(props) => props.$color}; + border-radius: 2px; + flex-shrink: 0; +`; + +const TrailStatusLegendLabel = styled.span` + color: #333; +`; + +const MAPBOX_TOKEN = process.env.REACT_APP_MAPBOX_API_TOKEN; + +const INTERACTIVE_LAYER_IDS = [ + "major-trails-layer", + "other-regional-trails-layer", + "gaps-other-regional-trails-layer", + "openspace-layer-regional", + "openspace-outline-regional" +]; + +const RegionalTrailsProfile = ({ + viewport, + setViewport, + baseLayer, + showBasemapPanel, + toggleBasemapPanel, + showControlPanel, + toggleControlPanel, + mapRef +}) => { + const navigate = useNavigate(); + const location = useLocation(); + const { + showTrailsRegNameSync, + setShowTrailsRegNameSync, + basemaps, + setProjectRegNames, + setSelectedProjectRegName, + showMunicipalities, + toggleMunicipalities, + showOpenSpace: showOpenSpaceFromContext, + setShowOpenSpace: setShowOpenSpaceFromContext, + showEnvironmentalJustice, + setShowEnvironmentalJustice, + } = useContext(LayerContext); + + const [showIdentifyPopup, toggleIdentifyPopup] = useState(false); + const [identifyInfo, setIdentifyInfo] = useState(null); + const [identifyPoint, setIdentifyPoint] = useState(null); + const [pointIndex, setPointIndex] = useState(0); + const [regNames, setRegNames] = useState([]); + const [selectedRegNames, setSelectedRegNames] = useState(new Set()); // Track selected projects (Set for easy toggle) + const [selectedMajorTrails, setSelectedMajorTrails] = useState([]); // Track selected major trails (array of grouped_reg_name values) + + // Reset selected projects when entering Regional Trails Profile and show municipalities by default + useEffect(() => { + if (location.pathname === '/regionalTrailsProfile') { + setSelectedRegNames(new Set()); + setSelectedMajorTrails([]); + // Show municipalities by default + toggleMunicipalities(true); + } + }, [location.pathname, toggleMunicipalities]); + const [hoveredTrail, setHoveredTrail] = useState(null); + const allRegNamesRef = useRef(new Set()); // Track all unique reg_names seen using ref + const [allTrailsData, setAllTrailsData] = useState(null); // Store all trail data from OtherRegionalTrailsLayer + const [majorTrailsData, setMajorTrailsData] = useState(null); // Store all major trail data from MajorTrailsLayer + + // Use global OpenSpace state instead of local state to persist across profile switches + const showOpenSpace = showOpenSpaceFromContext; + + const [openSpaceClickInfo, setOpenSpaceClickInfo] = useState(null); // Store OpenSpace click info for popup + + // Listen for OpenSpace toggle events (only for Regional Trails Profile) + useEffect(() => { + const handleToggleOpenSpace = (event) => { + if (location.pathname === '/regionalTrailsProfile') { + setShowOpenSpaceFromContext(event.detail.show); + // Zoom to level 11 when OpenSpace is opened, only if current zoom is smaller than 11 + if (event.detail.show && mapRef?.current) { + const map = mapRef.current.getMap(); + if (map && map.getZoom() < 11) { + map.easeTo({ + zoom: 11, + duration: 1000 + }); + } + } + } + }; + + window.addEventListener('toggleOpenSpace', handleToggleOpenSpace); + return () => { + window.removeEventListener('toggleOpenSpace', handleToggleOpenSpace); + }; + }, [location.pathname, setShowOpenSpaceFromContext, mapRef]); + + const [environmentalJusticeClickInfo, setEnvironmentalJusticeClickInfo] = useState(null); // Store Environmental Justice click info for popup + const [majorTrailClickInfo, setMajorTrailClickInfo] = useState(null); // Store Major Trail click info for popup + const [regularTrailClickInfo, setRegularTrailClickInfo] = useState(null); // Store Regular Trail click info for popup + const ejHoverTimeoutRef = useRef(null); + const ejHoverQueryIdRef = useRef(0); + + const getTrailTypeLabel = (segType, facStat) => + TRAIL_FACILITY_TYPE_LABELS[`${segType},${facStat}`] + + // Update reg_names in context when discovered + useEffect(() => { + if (regNames.length > 0) { + const previousSize = allRegNamesRef.current.size; + regNames.forEach(name => { + if (name && name.trim() !== "") { + allRegNamesRef.current.add(name); + } + }); + + if (allRegNamesRef.current.size !== previousSize) { + const sortedRegNames = Array.from(allRegNamesRef.current).sort(); + if (setProjectRegNames) setProjectRegNames(sortedRegNames); + } else if (setProjectRegNames) { + setProjectRegNames(regNames); + } + } + }, [regNames, setProjectRegNames]); + + // Update selected reg names in context + useEffect(() => { + if (setSelectedProjectRegName) { + // Convert Set to array for context (or pass first selected if single selection expected) + const selectedArray = Array.from(selectedRegNames); + setSelectedProjectRegName(selectedArray.length > 0 ? selectedArray[0] : null); + } + }, [selectedRegNames, setSelectedProjectRegName]); + + // Function to zoom to a specific project by regName (works for both regular projects and major trails) + const handleZoomToProject = (regName) => { + const map = mapRef.current?.getMap(); + if (!map || !regName) { + return false; + } + + let trailsToZoom = []; + + // Check if it's a major trail (check selectedMajorTrails) + if (selectedMajorTrails.includes(regName) && majorTrailsData && majorTrailsData.features) { + trailsToZoom = majorTrailsData.features.filter(feature => { + const groupedRegName = (feature.properties?.grouped_reg_name || "").trim(); + return groupedRegName === regName.trim(); + }); + } + // Otherwise, check regular projects + else if (allTrailsData && allTrailsData.features) { + trailsToZoom = allTrailsData.features.filter(feature => { + const featureRegName = (feature.properties?.reg_name || "").trim(); + return featureRegName === regName.trim(); + }); + } + + if (trailsToZoom.length === 0) { + return false; + } + + try { + // Create a FeatureCollection with the trails + const featureCollection = { + type: "FeatureCollection", + features: trailsToZoom + }; + + // Calculate bounding box + const bounds = bbox(featureCollection); + + // Fit map to bounds with padding + map.fitBounds( + [ + [bounds[0], bounds[1]], // Southwest corner + [bounds[2], bounds[3]] // Northeast corner + ], + { + padding: { top: 100, bottom: 100, left: 500, right: 80 }, + duration: 1000, + maxZoom: 12 + } + ); + return true; + } catch (e) { + console.warn("Error fitting bounds to project trails:", e); + return false; + } + }; + + // Zoom to trail when user checks a regional trail (other projects or major trails) + const previousSelectedRef = useRef(new Set()); + const previousMajorTrailsRef = useRef([]); + + useEffect(() => { + // Zoom when a new "other regional trail" project is selected + const newlySelected = Array.from(selectedRegNames).filter( + regName => !previousSelectedRef.current.has(regName) + ); + if (newlySelected.length > 0) { + const zoomed = handleZoomToProject(newlySelected[0]); + if (zoomed) { + previousSelectedRef.current = new Set(selectedRegNames); + } + } else { + previousSelectedRef.current = new Set(selectedRegNames); + } + }, [selectedRegNames, allTrailsData]); + + useEffect(() => { + // Zoom when a new major trail is selected + const newlySelected = selectedMajorTrails.filter( + name => !previousMajorTrailsRef.current.includes(name) + ); + if (newlySelected.length > 0) { + const zoomed = handleZoomToProject(newlySelected[0]); + if (zoomed) { + previousMajorTrailsRef.current = [...selectedMajorTrails]; + } + } else { + previousMajorTrailsRef.current = [...selectedMajorTrails]; + } + }, [selectedMajorTrails, majorTrailsData]); + + // Query Environmental Justice feature at a point + const queryEnvironmentalJusticeAtPoint = (lng, lat) => + queryFeatureAtPoint(`${EJ2020_MAP_SERVER_URL}/0`, lng, lat); + + const clearAllPopups = () => { + toggleIdentifyPopup(false); + setOpenSpaceClickInfo(null); + setEnvironmentalJusticeClickInfo(null); + setMajorTrailClickInfo(null); + setRegularTrailClickInfo(null); + }; + + const showPopup = (setter, data) => { + clearAllPopups(); + setTimeout(() => setter(data), 10); + }; + + const pt = (e) => ({ lng: e.lngLat.lng, lat: e.lngLat.lat }); + + /** + * Handle map click: show popup for clicked feature (OpenSpace, trails, EJ) or clear all. + * Order: OpenSpace > major trails > regular trails > EJ (raster, needs server query). + */ + const handleTrailClick = async (event) => { + const map = mapRef.current?.getMap(); + if (!map || !event.lngLat) { + clearAllPopups(); + return; + } + + // 1. OpenSpace (vector) + if (showOpenSpace) { + const feature = getFeaturesAtPoint(map, event, ["openspace-layer-regional", "openspace-outline-regional"]); + if (feature) { + const isSame = openSpaceClickInfo?.feature?.properties?.OBJECTID === feature.properties?.OBJECTID; + if (isSame) setOpenSpaceClickInfo(null); + else showPopup(setOpenSpaceClickInfo, { point: pt(event), feature }); + return; + } + } + + // 2. Major trails (vector) + if (selectedMajorTrails?.length) { + const feature = getFeaturesAtPoint(map, event, ["major-trails-layer"]); + if (feature) { + showPopup(setMajorTrailClickInfo, { point: pt(event), feature }); + return; + } + } + + // 3. Regular trails (vector) + const trailFeatures = getFeaturesAtPoint(map, event, ["other-regional-trails-layer", "gaps-other-regional-trails-layer"], { returnAll: true }); + if (trailFeatures.length) { + showPopup(setRegularTrailClickInfo, { point: pt(event), feature: trailFeatures[0] }); + return; + } + + // 4. EJ (raster - query server) + if (showEnvironmentalJustice) { + const ejFeature = await queryEnvironmentalJusticeAtPoint(event.lngLat.lng, event.lngLat.lat); + if (ejFeature) { + const isSame = environmentalJusticeClickInfo?.feature?.properties?.OBJECTID === ejFeature.properties?.OBJECTID; + if (isSame) setEnvironmentalJusticeClickInfo(null); + else showPopup(setEnvironmentalJusticeClickInfo, { point: pt(event), feature: ejFeature }); + return; + } + } + + clearAllPopups(); + }; + + /** + * Handle map hover: set hoveredTrail to control cursor (pointer when over clickable features) + * and layer hover highlights (thicker line on trails). + * + * Flow: + * - Vector layers (trails, OpenSpace): use queryRenderedFeatures - any feature from + * INTERACTIVE_LAYER_IDS = pointer. MajorTrailsLayer/OtherRegionalTrailsLayer need + * featureId in hoveredTrail for their hover highlight. + * - EJ layer (raster): no vector data on client - debounced point query to server. + */ + const handleTrailHover = (event) => { + const map = mapRef.current?.getMap(); + if (!map || !event.lngLat) { + setHoveredTrail(null); + return; + } + + const point = [event.lngLat.lng, event.lngLat.lat]; + let features = event.features; + if (!features) { + try { + features = map.queryRenderedFeatures(point); + } catch (err) { + setHoveredTrail(null); + return; + } + } + + // Vector layers: any feature from our layers = pointer (MajorTrailsLayer/OtherRegionalTrailsLayer need featureId for hover highlight) + const feature = features.find((f) => f.layer?.id && INTERACTIVE_LAYER_IDS.includes(f.layer.id)); + if (feature) { + const layerId = feature.layer.id; + if (layerId === "major-trails-layer") { + setHoveredTrail({ + properties: feature.properties, + lngLat: event.lngLat, + featureId: feature.properties?.OBJECTID ?? null, + isMajorTrail: true + }); + } else if (layerId === "other-regional-trails-layer" || layerId === "gaps-other-regional-trails-layer") { + setHoveredTrail({ + properties: feature.properties, + lngLat: event.lngLat, + featureId: feature.properties?.OBJECTID ?? null, + isRegularTrail: true + }); + } else { + setHoveredTrail({ isOpenSpace: true }); + } + return; + } + + // EJ: raster layer - must query server (no vector data on client) + if (showEnvironmentalJustice) { + if (ejHoverTimeoutRef.current) clearTimeout(ejHoverTimeoutRef.current); + const queryId = ++ejHoverQueryIdRef.current; + ejHoverTimeoutRef.current = setTimeout(() => { + queryEnvironmentalJusticeAtPoint(event.lngLat.lng, event.lngLat.lat).then((ejFeature) => { + if (queryId !== ejHoverQueryIdRef.current) return; + setHoveredTrail(ejFeature ? { isEnvironmentalJustice: true } : null); + }); + }, 150); + return; + } + + if (ejHoverTimeoutRef.current) { + clearTimeout(ejHoverTimeoutRef.current); + ejHoverTimeoutRef.current = null; + } + setHoveredTrail(null); + }; + + // Helper function to calculate metrics for a set of trails + const calculateTrailMetrics = (trails, name) => { + if (!trails || trails.length === 0) { + return { + totalLength: 0, + totalLengthMiles: 0, + municipalities: [] + }; + } + + // Calculate total length and categorize by status and type + let totalLengthFeet = 0; + let completedLengthFeet = 0; // fac_stat = 1 means existing/completed + const lengthByTypeExisting = {}; // Track length by trail type for existing trails + const lengthByTypePlanned = {}; // Track length by trail type for planned/envisioned/design trails + const gaps = []; // Track gaps (seg_type = 9) + + trails.forEach(trail => { + const props = trail.properties || {}; + const segType = props.seg_type; + const facStat = props.fac_stat; + const trailTypeLabel = getTrailTypeLabel(segType, facStat); + + const lengthFeet = Number(props.length_ft) || 0; + + totalLengthFeet += lengthFeet; + + // Track completed length (fac_stat = 1) + if (facStat === 1 || facStat === "1") { + completedLengthFeet += lengthFeet; + } + + // Track gaps (seg_type = 9) separately + if (segType === 9 || segType === "9") { + gaps.push({ + type: trailTypeLabel, + length: lengthFeet, + geometry: trail.geometry + }); + } else { + // Track length by type, separated into existing and planned + if (facStat === 1 || facStat === "1") { + // Existing trails + if (!lengthByTypeExisting[trailTypeLabel]) { + lengthByTypeExisting[trailTypeLabel] = 0; + } + lengthByTypeExisting[trailTypeLabel] += lengthFeet; + } else { + // Planned trails (fac_stat = 2 or other values) + if (!lengthByTypePlanned[trailTypeLabel]) { + lengthByTypePlanned[trailTypeLabel] = 0; + } + lengthByTypePlanned[trailTypeLabel] += lengthFeet; + } + } + }); + + const totalLengthMiles = totalLengthFeet / 5280; + const completedLengthMiles = completedLengthFeet / 5280; + const percentageComplete = totalLengthFeet > 0 + ? ((completedLengthFeet / totalLengthFeet) * 100).toFixed(1) + : 0; + + // Determine which municipalities the trails are in using muni_id from feature properties + const municipalitySet = new Set(); + + // Extract muni_id from trail properties and look up municipality name + trails.forEach(trail => { + const props = trail.properties || {}; + // Try different possible field names for muni_id + const muniId = props.muni_id || null; + + if (muniId) { + const muniName = getMunicipalityName(muniId); + if (muniName) { + municipalitySet.add(muniName); + } + } + }); + + // Parks intersection calculation removed - using VectorTileServer now + const parksSet = new Set(); + + // Get trail steward and website from first trail (assuming they're consistent for a project) + const firstTrail = trails[0]; + const steward = firstTrail?.properties?.steward || + firstTrail?.properties?.Steward || + firstTrail?.properties?.STEWARD || + null; + const website = firstTrail?.properties?.website || + firstTrail?.properties?.Website || + firstTrail?.properties?.WEBSITE || + firstTrail?.properties?.url || + firstTrail?.properties?.URL || + null; + + // Convert lengthByType to arrays with miles, separated by existing, planned, and gap + const lengthByTypeExistingArray = Object.entries(lengthByTypeExisting).map(([type, feet]) => ({ + type, + miles: (feet / 5280).toFixed(2), + category: 'existing' + })); + + const lengthByTypePlannedArray = Object.entries(lengthByTypePlanned).map(([type, feet]) => ({ + type, + miles: (feet / 5280).toFixed(2), + category: 'planned' + })); + + const lengthByTypeGapArray = gaps.map(gap => ({ + type: gap.type, + miles: (gap.length / 5280).toFixed(2), + category: 'gap' + })); + + // Combine all length by type into a single array with categories + const lengthByTypeArray = [ + ...lengthByTypeExistingArray.map(item => ({ ...item, category: 'existing' })), + ...lengthByTypePlannedArray.map(item => ({ ...item, category: 'planned' })), + ...lengthByTypeGapArray.map(item => ({ ...item, category: 'gap' })) + ]; + + return { + totalLength: totalLengthFeet, + totalLengthMiles: totalLengthMiles.toFixed(2), + completedLengthMiles: completedLengthMiles.toFixed(2), + percentageComplete: percentageComplete, + municipalities: Array.from(municipalitySet).sort(), + parks: Array.from(parksSet).sort(), + steward: steward, + website: website, + lengthByType: lengthByTypeArray, + gaps: gaps.map(gap => ({ + type: gap.type, + lengthMiles: (gap.length / 5280).toFixed(2) + })) + }; + }; + + // Calculate metrics for selected projects and major trails (including hidden ones for metrics display) + const projectMetrics = useMemo(() => { + const metrics = {}; + + // Process each selected regular project (include hidden ones for metrics) + if (allTrailsData && allTrailsData.features && selectedRegNames.size > 0) { + Array.from(selectedRegNames).forEach(regName => { + // Filter trails for this project + const projectTrails = allTrailsData.features.filter( + feature => (feature.properties?.reg_name || "").trim() === regName.trim() + ); + + metrics[regName] = calculateTrailMetrics(projectTrails, regName); + }); + } + + // Process each selected major trail + if (majorTrailsData && majorTrailsData.features && selectedMajorTrails.length > 0) { + selectedMajorTrails.forEach(majorTrailName => { + // Filter trails for this major trail by grouped_reg_name + const majorTrailTrails = majorTrailsData.features.filter( + feature => { + const groupedRegName = (feature.properties?.grouped_reg_name || "").trim(); + return groupedRegName === majorTrailName.trim(); + } + ); + + metrics[majorTrailName] = calculateTrailMetrics(majorTrailTrails, majorTrailName); + }); + } + + return metrics; + }, [allTrailsData, selectedRegNames, majorTrailsData, selectedMajorTrails]); + + + // Get all layer IDs for trails reg name sync (always include trail layers for click detection) + const getTrailLayerIds = () => { + const layerIds = []; + // Always add regular trail layers for click detection (even if no projects selected) + layerIds.push("other-regional-trails-layer"); + layerIds.push("gaps-other-regional-trails-layer"); + // Add Major Trail layer if major trails are selected (now includes gaps) + if (selectedMajorTrails && selectedMajorTrails.length > 0) { + layerIds.push("major-trails-layer"); + } + // Add OpenSpace layers if OpenSpace is shown + if (showOpenSpace) { + layerIds.push("openspace-layer-regional"); + layerIds.push("openspace-outline-regional"); + } + // Add Environmental Justice layer if shown + if (showEnvironmentalJustice) { + layerIds.push("environmental-justice-layer-regional"); + } + // Don't add municipalities-fill to interactive layers since we don't want hover + return layerIds; + }; + + // Municipality layers function - always show, no hover + const municipalitiesLayers = () => { + const visibleMunicipalitiesLayers = []; + // Always show municipalities in regional trails profile + visibleMunicipalitiesLayers.push( + + ); + return visibleMunicipalitiesLayers; + }; + + // Ensure trails layers are always on top + useEffect(() => { + if (!mapRef?.current) return; + + const map = mapRef.current.getMap(); + if (!map) return; + + const ensureTrailsOnTop = () => { + if (!map.isStyleLoaded()) { + map.once('styledata', ensureTrailsOnTop); + return; + } + + try { + // Complete list of all trail layer IDs that should be on top + const trailLayerIds = [ + 'other-regional-trails-layer', + 'other-regional-trails-layer-hover', + 'other-regional-trails-layer-click', + 'gaps-other-regional-trails-layer', + 'major-trails-layer', + 'major-trails-layer-hover', + 'major-trails-layer-click' + ]; + + // Get all layer IDs in the current style + const style = map.getStyle(); + if (!style || !style.layers) return; + + const allLayerIds = style.layers.map(layer => layer.id); + + // Filter to get only existing trail layers + const existingTrailLayers = trailLayerIds.filter(id => map.getLayer(id)); + + if (existingTrailLayers.length === 0) return; + + // Find all non-trail layer IDs + const nonTrailLayerIds = allLayerIds.filter(id => !trailLayerIds.includes(id)); + + if (nonTrailLayerIds.length === 0) return; + + // Find the last non-trail layer ID - we'll move all trail layers after this + const lastNonTrailLayerId = nonTrailLayerIds[nonTrailLayerIds.length - 1]; + + // Move each trail layer to be after the last non-trail layer + // Process in order to maintain relative order among trail layers + existingTrailLayers.forEach(trailLayerId => { + try { + // Check current position + const currentBeforeId = map.getLayer(trailLayerId)?.metadata?.beforeId; + + // Only move if not already in correct position + // Move to be after the last non-trail layer + map.moveLayer(trailLayerId, lastNonTrailLayerId); + } catch (err) { + // Layer might not exist or already in correct position - ignore + } + }); + } catch (err) { + // Silently fail if there's an error + console.warn('Error ensuring trails on top:', err); + } + }; + + // Wait a bit for layers to be added + const timeoutId = setTimeout(ensureTrailsOnTop, 500); + + // Also listen for style changes and map movements + map.on('styledata', ensureTrailsOnTop); + map.on('moveend', ensureTrailsOnTop); + map.on('zoomend', ensureTrailsOnTop); + + return () => { + clearTimeout(timeoutId); + if (map && map.off) { + map.off('styledata', ensureTrailsOnTop); + map.off('moveend', ensureTrailsOnTop); + map.off('zoomend', ensureTrailsOnTop); + } + }; + }, [mapRef, selectedRegNames, selectedMajorTrails, showOpenSpace, showEnvironmentalJustice]); + + // Ensure baseLayer and MAPBOX_TOKEN exist before rendering + if (!baseLayer || !baseLayer.url || !MAPBOX_TOKEN) { + return null; + } + + return ( +
+ { + setViewport(event.viewState); + }} + onClick={handleTrailClick} + onMouseMove={handleTrailHover} + onMouseLeave={() => { + if (ejHoverTimeoutRef.current) { + clearTimeout(ejHoverTimeoutRef.current); + ejHoverTimeoutRef.current = null; + } + setHoveredTrail(null); + }} + mapboxAccessToken={MAPBOX_TOKEN} + mapStyle={baseLayer.url} + scrollZoom={true} + transitionDuration="1000" + transformRequest={(url, resourceType) => { + // Only transform non-Mapbox tile requests (e.g. ArcGIS VectorTileServer) + if (resourceType === 'Tile' && !url.includes('mapbox.com') && url.includes('VectorTileServer/tile/')) { + const convertedUrl = url.replace(/\/tile\/(\d+)\/(\d+)\/(\d+)\.pbf/, (match, z, y, x) => { + return `/tile/${z}/${x}/${y}.pbf`; + }); + return { url: convertedUrl }; + } + return { url }; + }} + > + {/* Municipality Map Layer - always visible */} + + {municipalitiesLayers()} + + + {/* OpenSpace Layer - rendered before trails to ensure trails appear on top */} + {showOpenSpace && ( + + )} + + {/* Environmental Justice Layer - rendered before trails to ensure trails appear on top */} + {showEnvironmentalJustice && ( + + )} + + {/* Major Trails Layer - rendered after other layers to appear on top */} + 0} + showRegionalTrailsProfile={true} + mapRef={mapRef} + selectedMajorTrails={selectedMajorTrails} + onTrailsDataChange={setMajorTrailsData} + hoveredTrail={ + hoveredTrail && (hoveredTrail.properties?.grouped_reg_name || hoveredTrail.isMajorTrail) + ? hoveredTrail + : null + } + clickedTrail={majorTrailClickInfo ? { + featureId: majorTrailClickInfo.feature.properties?.OBJECTID + } : null} + /> + + {/* other regional trails layer - rendered last to appear on top of all other layers */} + + + {/* No hover popup for regular trails - only show on click */} + + {/* Identify popup */} + {showIdentifyPopup && identifyPoint && identifyInfo && identifyInfo.length > 0 && ( + { + toggleIdentifyPopup(false); + }} + handleCarousel={setPointIndex} + /> + )} + + {/* Environmental Justice Click Popup */} + {showEnvironmentalJustice && environmentalJusticeClickInfo?.point && environmentalJusticeClickInfo?.feature && ( + setEnvironmentalJusticeClickInfo(null)} + anchor="top" + offset={12} + > + + + )} + + {/* Major Trail Click Popup */} + {selectedMajorTrails && selectedMajorTrails.length > 0 && majorTrailClickInfo && majorTrailClickInfo.point && majorTrailClickInfo.feature && ( + setMajorTrailClickInfo(null)} + anchor="top" + offset={12} + > + + + )} + + {/* Regular Trail Click Popup */} + {regularTrailClickInfo && regularTrailClickInfo.point && regularTrailClickInfo.feature && ( + setRegularTrailClickInfo(null)} + anchor="top" + offset={12} + > + + + )} + + {/* OpenSpace Click Popup */} + {showOpenSpace && openSpaceClickInfo?.point && openSpaceClickInfo?.feature && ( + setOpenSpaceClickInfo(null)} + anchor="top" + offset={12} + > + + + )} + + {/* Geocoder - styled to appear inside control panel */} + + + {/* Map controls */} + + + + + {/* Trail Status Legend - only show when trails are selected */} + {(selectedRegNames.size > 0 || selectedMajorTrails.length > 0) && ( + + Trail Status + + + + Existing + + + + Planned/Envisioned/Design + + + + Gap + + + + )} + + {/* Control Panel Toggle Button */} + toggleControlPanel(!showControlPanel)} + /> + + + + {/* Basemap Panel */} + {showBasemapPanel && ( + + )} + + {/* Control Panel */} + {showControlPanel && ( +
+ { + const newSelected = new Set(selectedRegNames); + if (newSelected.has(regName)) { + newSelected.delete(regName); + } else { + newSelected.add(regName); + } + setSelectedRegNames(newSelected); + }} + onToggleMajorTrail={(majorTrailName) => { + const newSelected = [...selectedMajorTrails]; + const index = newSelected.indexOf(majorTrailName); + if (index > -1) { + newSelected.splice(index, 1); + } else { + newSelected.push(majorTrailName); + } + setSelectedMajorTrails(newSelected); + }} + /> +
+ )} + + {/* Regional Trails Metrics Panel - separate window on the left */} + +
+ ); +}; + +export default RegionalTrailsProfile; + diff --git a/src/components/Map/TrailLegend.js b/src/components/Map/TrailLegend.js index 8113e66..b4edfd0 100644 --- a/src/components/Map/TrailLegend.js +++ b/src/components/Map/TrailLegend.js @@ -1,6 +1,6 @@ import React from 'react'; import '../../styles/TrailLegend.scss'; -import { geojsonTrailLayers } from './constants/geojsonTrailLayers'; +import { trailsProfileLayers } from './constants/mapConstants'; const TrailLegend = ({ visibleTrailTypes, onToggleTrailType }) => { // If no visibility state provided, show all by default @@ -16,8 +16,8 @@ const TrailLegend = ({ visibleTrailTypes, onToggleTrailType }) => { }; // Separate trails into existing and planned - const existingTrails = geojsonTrailLayers.filter(layer => !layer.name.includes('Planned')); - const plannedTrails = geojsonTrailLayers.filter(layer => layer.name.includes('Planned')); + const existingTrails = trailsProfileLayers.filter(layer => !layer.name.includes('Planned')); + const plannedTrails = trailsProfileLayers.filter(layer => layer.name.includes('Planned')); const renderTrailItem = (layer) => { const visible = isVisible(layer.id); diff --git a/src/components/Map/TrailLegend.scss b/src/components/Map/TrailLegend.scss deleted file mode 100644 index c54b2f3..0000000 --- a/src/components/Map/TrailLegend.scss +++ /dev/null @@ -1,74 +0,0 @@ -.TrailLegend { - position: absolute; - bottom: 120px; // Position above the map controls - right: 10px; - background: rgba(255, 255, 255, 0.95); - border: 1px solid rgba(0, 0, 0, 0.1); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); - border-radius: 6px; - padding: 12px; - z-index: 1000; - max-width: 280px; - font-size: 12px; - max-height: 60vh; - overflow-y: auto; - - &__header { - margin-bottom: 8px; - padding-bottom: 6px; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); - font-size: 13px; - } - - &__section { - margin-bottom: 12px; - - &:last-child { - margin-bottom: 0; - } - } - - &__section-header { - margin-bottom: 6px; - padding-bottom: 4px; - border-bottom: 1px solid rgba(0, 0, 0, 0.08); - } - - &__items { - display: flex; - flex-direction: column; - gap: 6px; - } - - &__item { - display: flex; - align-items: center; - gap: 8px; - } - - &__icon { - color: #666; - transition: color 0.2s ease; - - &:hover { - color: #333; - } - } - - &__line-container { - flex-shrink: 0; - display: flex; - align-items: center; - } - - &__line { - display: block; - } - - &__label { - flex: 1; - line-height: 1.3; - color: #333; - } -} - diff --git a/src/components/Map/constants/geojsonTrailLayers.js b/src/components/Map/constants/geojsonTrailLayers.js deleted file mode 100644 index 139eb90..0000000 --- a/src/components/Map/constants/geojsonTrailLayers.js +++ /dev/null @@ -1,17 +0,0 @@ -// GeoJSON trail layer definitions - using local files -// Colors match LayerData.js for consistency -export const geojsonTrailLayers = [ - { id: 0, name: "Protected Bike Lanes", filename: "existing_protected_bike_lanes.json", color: "#2166AC" }, - { id: 1, name: "Planned Protected Bike Lanes", filename: "planned_protected_bike_lanes.json", color: "#2166AC", dashArray: [2, 2] }, - { id: 2, name: "Bike Lanes", filename: "existing_bike_lanes.json", color: "#92C5DE" }, - { id: 3, name: "Planned Bike Lanes", filename: "proposed_bike_lanes.json", color: "#92C5DE", dashArray: [2, 2] }, - { id: 4, name: "Paved Foot Path", filename: "paved_footway.json", color: "#903366" }, - { id: 5, name: "Planned Paved Foot Path", filename: "proposed_paved_footway.json", color: "#903366", dashArray: [2, 2] }, - { id: 6, name: "Natural Surface Path", filename: "natural_surface_footway.json", color: "#A87196" }, - { id: 7, name: "Planned Natural Surface Path", filename: "proposed_natural_surface_footway.json", color: "#A87196", dashArray: [2, 2] }, - { id: 8, name: "Paved Shared Use", filename: "existing_paved_shared_use_paths.json", color: "#214A2D" }, - { id: 9, name: "Planned Paved Shared Use", filename: "proposed_paved_shared_use_paths.json", color: "#214A2D", dashArray: [2, 2] }, - { id: 10, name: "Planned Unimproved Shared Use", filename: "proposed_unimproved_shared_use_paths.json", color: "#4BAA40", dashArray: [2, 2] }, - { id: 11, name: "Unimproved Shared Use", filename: "existing_unimproved_shared_use_paths.json", color: "#4BAA40" } -]; - diff --git a/src/components/Map/constants/mapConstants.js b/src/components/Map/constants/mapConstants.js index b33744d..7c98524 100644 --- a/src/components/Map/constants/mapConstants.js +++ b/src/components/Map/constants/mapConstants.js @@ -1,5 +1,65 @@ -export const FEATURE_SERVER_BASE = - "https://geo.mapc.org/server/rest/services/transportation/AllTrails/FeatureServer"; +/** + * Map-related constants for trails, layers, and facility types. + */ -export const DEFAULT_BUFFER_RADIUS = 1609; // Default: 1 mile in meters +// ----------------------------------------------------------------------------- +// Trails Profile Layers (Community Trails Profile) +// Layer definitions using local GeoJSON files. +// Colors match LayerData.js for consistency. +// ----------------------------------------------------------------------------- +export const trailsProfileLayers = [ + { id: 0, name: "Protected Bike Lanes", filename: "existing_protected_bike_lanes.json", color: "#2166AC" }, + { id: 1, name: "Planned Protected Bike Lanes", filename: "planned_protected_bike_lanes.json", color: "#2166AC", dashArray: [2, 2] }, + { id: 2, name: "Bike Lanes", filename: "existing_bike_lanes.json", color: "#92C5DE" }, + { id: 3, name: "Planned Bike Lanes", filename: "proposed_bike_lanes.json", color: "#92C5DE", dashArray: [2, 2] }, + { id: 4, name: "Paved Foot Path", filename: "paved_footway.json", color: "#903366" }, + { id: 5, name: "Planned Paved Foot Path", filename: "proposed_paved_footway.json", color: "#903366", dashArray: [2, 2] }, + { id: 6, name: "Natural Surface Path", filename: "natural_surface_footway.json", color: "#A87196" }, + { id: 7, name: "Planned Natural Surface Path", filename: "proposed_natural_surface_footway.json", color: "#A87196", dashArray: [2, 2] }, + { id: 8, name: "Paved Shared Use", filename: "existing_paved_shared_use_paths.json", color: "#214A2D" }, + { id: 9, name: "Planned Paved Shared Use", filename: "proposed_paved_shared_use_paths.json", color: "#214A2D", dashArray: [2, 2] }, + { id: 10, name: "Planned Unimproved Shared Use", filename: "proposed_unimproved_shared_use_paths.json", color: "#4BAA40", dashArray: [2, 2] }, + { id: 11, name: "Unimproved Shared Use", filename: "existing_unimproved_shared_use_paths.json", color: "#4BAA40" } +]; +// ----------------------------------------------------------------------------- +// Environmental Justice 2020 MapServer (for query and export) +// Fallback for when REACT_APP_EJ2020_MAP_SERVER_URL is not set (e.g. dev server not restarted) +// ----------------------------------------------------------------------------- +export const EJ2020_MAP_SERVER_URL = + process.env.REACT_APP_EJ2020_MAP_SERVER_URL || + "https://arcgisserver.digital.mass.gov/arcgisserver/rest/services/AGOL/EJ2020/MapServer"; + +// ----------------------------------------------------------------------------- +// Trail Facility Type Labels (Regional Trails / FeatureServer) +// Maps seg_type,fac_stat to human-readable labels for display in popups and UI. +// Key format: "seg_type,fac_stat" (e.g. "1,1" = Shared Use Path, Existing) +// fac_stat: 1 = Existing, 2 = Design/Construction, 3 = Envisioned +// ----------------------------------------------------------------------------- +export const TRAIL_FACILITY_TYPE_LABELS = { + "1,1": "Shared Use Path - Existing", + "1,2": "Shared Use Path - Design", + "1,3": "Shared Use Path - Envisioned", + "6,3": "Shared Use Path - Unimproved Surface", + "6,1": "Shared Use Path - Unimproved Surface", + "6,2": "Shared Use Path - Unimproved Surface", + "2,1": "Protected Bike Lane and Sidewalk", + "2,2": "Protected Bike Lane - Design or Construction", + "2,3": "Protected Bike Lane - Design or Construction", + "3,1": "Bike Lane and Sidewalk", + "3,2": "Bike Lane - Design or Construction", + "3,3": "Bike Lane - Design or Construction", + "4,3": "Shared Street - Urban", + "4,1": "Shared Street - Urban", + "5,1": "Shared Street - Suburban", + "5,3": "Shared Street - Envisioned", + "9,1": "Gap - Facility Type TBD", + "9,2": "Gap - Facility Type TBD", + "9,3": "Gap - Facility Type TBD", + "11,1": "Foot Trail - Natural Surface", + "11,3": "Foot Trail - Envisioned Natural Surface", + "11,2": "Foot Trail - Envisioned Natural Surface", + "12,1": "Foot Trail - Roadway Section", + "12,2": "Foot Trail - Envisioned Roadway Section", + "12,3": "Foot Trail - Envisioned Roadway Section" +}; diff --git a/src/components/Map/index.js b/src/components/Map/index.js index 458eb9f..9daa58e 100644 --- a/src/components/Map/index.js +++ b/src/components/Map/index.js @@ -18,8 +18,8 @@ import MASenateDistrictsButton from '../MASenateDistrictsButton'; import MunicipalitiesButton from '../MunicipalitiesButton'; import GeocoderPanel from "../Geocoder/GeocoderPanel"; import GlossaryModal from "../Modals/GlossaryModal"; -import Identify from "./Identify"; -import CommunityIdentify from "./CommunityIdentify"; +import Identify from "./tooltip/Identify"; +import CommunityIdentify from "./tooltip/CommunityIdentify"; import ShareModal from "../Modals/ShareModal"; import { ModalContext } from "../../App"; import { LayerContext } from "../../App"; @@ -34,9 +34,9 @@ import * as turf from "@turf/turf"; // Extracted components import CommunityTrailsProfile from "./CommunityTrailsProfile"; import OriginalTrailsMap from "./OriginalTrailsMap"; -import ProjectTrailsProfile from "./ProjectTrailsProfile"; +import RegionalTrailsProfile from "./RegionalTrailsProfile"; // Extracted constants -import { geojsonTrailLayers } from "./constants/geojsonTrailLayers"; +import { trailsProfileLayers } from "./constants/mapConstants"; const MAPBOX_TOKEN = process.env.REACT_APP_MAPBOX_API_TOKEN; const TRAILMAP_SOURCE = process.env.REACT_APP_TRAIL_MAP_TILE_URL; @@ -67,8 +67,8 @@ const Map = () => { setMunicipalityTrails, showMunicipalityProfileMap, showMunicipalityView, - showProjectTrailsProfileMap, - showProjectTrailsView, + showRegionalTrailsProfileMap, + showRegionalTrailsView, // Layer toggle states from context showCommuterRail, setShowCommuterRail, @@ -127,15 +127,15 @@ const Map = () => { setMapParam(); }, []); - // Auto-switch to light basemap when entering municipality or project trails profile + // Auto-switch to light basemap when entering municipality or regional trails profile useEffect(() => { - if (showMunicipalityProfileMap || showProjectTrailsProfileMap) { + if (showMunicipalityProfileMap || showRegionalTrailsProfileMap) { const lightBasemap = basemaps.find((bm) => bm.id === 'mapboxLight'); if (lightBasemap && baseLayer.id !== 'mapboxLight') { setBaseLayer(lightBasemap); } } - }, [showMunicipalityProfileMap, showProjectTrailsProfileMap, basemaps, baseLayer, setBaseLayer]); + }, [showMunicipalityProfileMap, showRegionalTrailsProfileMap, basemaps, baseLayer, setBaseLayer]); const generateShareUrl = () => { return `${window.location.href.split("?")[0]}?baseLayer=${baseLayer.id}&trailLayers=${trailLayers.join( @@ -151,8 +151,8 @@ const Map = () => {
- {showProjectTrailsProfileMap ? ( - { /> )} - {/* Share Control Button - hidden in community trails profile */} - {!showMunicipalityProfileMap && ( + {/* Share Control Button - hidden in community trails profile and regional trails profile */} + {!showMunicipalityProfileMap && !showRegionalTrailsProfileMap && ( { const layerTrails = trailsByLayer[layerId]; - const layerInfo = geojsonTrailLayers.find(l => l.id === parseInt(layerId)); + const layerInfo = trailsProfileLayers.find(l => l.id === parseInt(layerId)); // Check if this trail type is visible (default to true if not specified) const isVisible = visibleTrailTypes[layerId] !== false; @@ -104,7 +105,7 @@ const CommunityTrailsProfileLayers = ({ }; // Add dash array if the trail has one - const layerInfo = geojsonTrailLayers.find(l => l.id === highlightedTrail.layerId); + const layerInfo = trailsProfileLayers.find(l => l.id === highlightedTrail.layerId); if (layerInfo && layerInfo.dashArray) { highlightPaint["line-dasharray"] = layerInfo.dashArray; } diff --git a/src/components/Map/layers/EnvironmentalJusticeLayer.js b/src/components/Map/layers/EnvironmentalJusticeLayer.js index 18a4f34..6813d86 100644 --- a/src/components/Map/layers/EnvironmentalJusticeLayer.js +++ b/src/components/Map/layers/EnvironmentalJusticeLayer.js @@ -1,5 +1,6 @@ import React, { useEffect, useState, useRef } from "react"; import { Source, Layer } from "react-map-gl"; +import { EJ2020_MAP_SERVER_URL } from "../constants/mapConstants"; /** * Renders Environmental Justice 2020 layer @@ -9,13 +10,13 @@ import { Source, Layer } from "react-map-gl"; * Note: This creates a single image overlay that updates with map movement. * For better performance with large datasets, consider using a tile proxy service. */ -const EnvironmentalJusticeLayer = ({ showEnvironmentalJustice, showMunicipalityProfileMap, showProjectTrailsProfile, mapRef }) => { +const EnvironmentalJusticeLayer = ({ showEnvironmentalJustice, showMunicipalityProfileMap, showRegionalTrailsProfile, mapRef }) => { const [imageUrl, setImageUrl] = useState(null); const [bounds, setBounds] = useState(null); const updateTimeoutRef = useRef(null); useEffect(() => { - if (!showEnvironmentalJustice || (!showMunicipalityProfileMap && !showProjectTrailsProfile) || !mapRef?.current) { + if (!showEnvironmentalJustice || (!showMunicipalityProfileMap && !showRegionalTrailsProfile) || !mapRef?.current) { setImageUrl(null); setBounds(null); return; @@ -40,7 +41,6 @@ const EnvironmentalJusticeLayer = ({ showEnvironmentalJustice, showMunicipalityP const swMerc = toWebMercator(sw.lng, sw.lat); const neMerc = toWebMercator(ne.lng, ne.lat); - const EJ2020_SERVICE_URL = "https://arcgisserver.digital.mass.gov/arcgisserver/rest/services/AGOL/EJ2020/MapServer"; const bbox = `${swMerc.x},${swMerc.y},${neMerc.x},${neMerc.y}`; // Get map size for export @@ -48,7 +48,7 @@ const EnvironmentalJusticeLayer = ({ showEnvironmentalJustice, showMunicipalityP const width = mapSize.clientWidth || 1024; const height = mapSize.clientHeight || 768; - const url = `${EJ2020_SERVICE_URL}/export?bbox=${bbox}&bboxSR=3857&imageSR=3857&size=${width},${height}&f=image&format=png&transparent=true&layers=show:0`; + const url = `${EJ2020_MAP_SERVER_URL}/export?bbox=${bbox}&bboxSR=3857&imageSR=3857&size=${width},${height}&f=image&format=png&transparent=true&layers=show:0`; setImageUrl(url); setBounds([ @@ -81,9 +81,9 @@ const EnvironmentalJusticeLayer = ({ showEnvironmentalJustice, showMunicipalityP } }; } - }, [showEnvironmentalJustice, showMunicipalityProfileMap, showProjectTrailsProfile, mapRef]); + }, [showEnvironmentalJustice, showMunicipalityProfileMap, showRegionalTrailsProfile, mapRef]); - if (!showEnvironmentalJustice || !showMunicipalityProfileMap || !imageUrl || !bounds) { + if (!showEnvironmentalJustice || (!showMunicipalityProfileMap && !showRegionalTrailsProfile) || !imageUrl || !bounds) { return null; } diff --git a/src/components/Map/layers/MajorTrailsLayer.js b/src/components/Map/layers/MajorTrailsLayer.js new file mode 100644 index 0000000..2a86d60 --- /dev/null +++ b/src/components/Map/layers/MajorTrailsLayer.js @@ -0,0 +1,284 @@ +import React, { useEffect, useState, useRef } from "react"; +import { Source, Layer } from "react-map-gl"; + +/** + * Renders Major Trails layer from ArcGIS FeatureServer + * Data source: https://services.arcgis.com/c5WwApDsDjRhIVkH/arcgis/rest/services/export_major_trails/FeatureServer + * + * Uses FeatureServer query endpoint to fetch GeoJSON features filtered by grouped_reg_name. + * When selectedMajorTrails is provided, only shows trails matching those grouped_reg_name values. + */ +const MajorTrailsLayer = ({ + showMajorTrails, + showRegionalTrailsProfile, + mapRef, + selectedMajorTrails = [], // Array of selected major trail names (grouped_reg_name values) + onTrailsDataChange = null, // Callback to pass trail data to parent (for metrics) + hoveredTrail = null, // Hovered trail object with featureId + clickedTrail = null // Clicked trail object with featureId +}) => { + const [trailsData, setTrailsData] = useState(null); + const updateTimeoutRef = useRef(null); + const queryTimeoutRef = useRef(null); + const accumulatedTrailsRef = useRef(new Map()); // Store trails by feature ID to avoid duplicates + + // Determine if layer should be shown + const shouldShow = showMajorTrails && showRegionalTrailsProfile; + + // ArcGIS token for authentication + const ARCGIS_TOKEN = "AAPTxy8BH1VEsoebNVZXo8HurFEryhzMUuo6HFsZYNxtvAILm5qQYklTujgW8rejiSVEA_kTru4Y7QuNe5-QWMtEpK-_L9TLSHlHV4h_oeYUONaR40fn8mVNBCPvWBSuheHtx9FPMu5xWNxz4gqnZ-TPnErmJVpoN7thS4Zj2QiLg12SqmtHyaMnnYJH5AwdRA1VAFZLZrfwWTLw4zLogHqqonCw58CKKRJS4rqd-UgsAO8.AT1_U0702ST1"; + + // FeatureServer URL + const FEATURE_SERVER_URL = "https://services.arcgis.com/c5WwApDsDjRhIVkH/arcgis/rest/services/export_major_trails/FeatureServer/0"; + + useEffect(() => { + if (!shouldShow || !mapRef?.current || !selectedMajorTrails || selectedMajorTrails.length === 0) { + setTrailsData(null); + accumulatedTrailsRef.current.clear(); + if (onTrailsDataChange) { + onTrailsDataChange(null); + } + return; + } + + const updateLayer = () => { + const map = mapRef.current?.getMap(); + if (!map) return; + + // Build where clause based on selected major trails + const escapedTrails = selectedMajorTrails.map(trail => + `'${trail.replace(/'/g, "''")}'` + ); + const whereClause = `grouped_reg_name IN (${escapedTrails.join(',')})`; + + // Query all trails for selected major trails regardless of map bounds/zoom level + const url = `${FEATURE_SERVER_URL}/query?where=${encodeURIComponent(whereClause)}&outFields=*&outSR=4326&f=geojson&returnGeometry=true&maxRecordCount=10000&token=${ARCGIS_TOKEN}`; + + // Debounce queries (reduced delay for better UX) + if (queryTimeoutRef.current) { + clearTimeout(queryTimeoutRef.current); + } + + queryTimeoutRef.current = setTimeout(async () => { + try { + const response = await fetch(url); + const data = await response.json(); + + if (data.error) { + console.error("FeatureServer error:", data.error); + return; + } + + if (data.features && data.features.length > 0) { + // Replace data entirely (don't accumulate) since we're fetching all trails for selected projects + accumulatedTrailsRef.current.clear(); + data.features.forEach(feature => { + const featureId = feature.properties?.OBJECTID || + feature.properties?.objectid || + feature.id || + JSON.stringify(feature.geometry); + accumulatedTrailsRef.current.set(featureId, feature); + }); + + const featureCollection = { + type: "FeatureCollection", + features: data.features + }; + setTrailsData(featureCollection); + + // Notify parent component of trail data changes for metrics + if (onTrailsDataChange) { + onTrailsDataChange(featureCollection); + } + } else { + // No features returned - clear data + accumulatedTrailsRef.current.clear(); + setTrailsData(null); + if (onTrailsDataChange) { + onTrailsDataChange(null); + } + } + } catch (error) { + console.error("Error fetching Major Trails data:", error); + if (accumulatedTrailsRef.current.size === 0) { + setTrailsData(null); + } + } + }, 100); + }; + + // Clear accumulated data when selectedMajorTrails changes + accumulatedTrailsRef.current.clear(); + + // Initial update + updateLayer(); + + // No need to update on map move since we're fetching all trails regardless of bounds + return () => { + if (updateTimeoutRef.current) { + clearTimeout(updateTimeoutRef.current); + } + if (queryTimeoutRef.current) { + clearTimeout(queryTimeoutRef.current); + } + }; + }, [shouldShow, mapRef, selectedMajorTrails, onTrailsDataChange]); + + if (!shouldShow || !trailsData || !trailsData.features || trailsData.features.length === 0) { + return null; + } + + // Filter trails based on selected major trails + let filteredTrailsData = trailsData; + if (selectedMajorTrails && selectedMajorTrails.length > 0) { + filteredTrailsData = { + type: "FeatureCollection", + features: trailsData.features.filter(feature => { + const groupedRegName = (feature.properties?.grouped_reg_name || "").trim(); + return selectedMajorTrails.some(selected => { + const normalizedSelected = (selected || "").trim(); + return normalizedSelected === groupedRegName; + }); + }) + }; + } else { + return null; // Don't show anything if no major trails selected + } + + if (!filteredTrailsData.features || filteredTrailsData.features.length === 0) { + return null; + } + + // Get hovered and clicked feature IDs for highlights + const hoveredFeatureId = hoveredTrail?.featureId; + const clickedFeatureId = clickedTrail?.featureId; + + // fac_stat can be number 1 or string "1" from ArcGIS - check both for existing (blue) + const isExistingTrail = ["any", ["==", ["get", "fac_stat"], 1], ["==", ["get", "fac_stat"], "1"]]; + + return ( + + {/* Combined trails layer - gaps in red, existing in blue, planned/envisioned/design in green */} + + {/* Hover layer - thicker line when hovering */} + + {/* Click highlight layer - thicker line when clicked, persists until tooltip closes */} + + + ); +}; + +export default MajorTrailsLayer; diff --git a/src/components/Map/layers/OpenSpaceLayer.js b/src/components/Map/layers/OpenSpaceLayer.js index fcd8108..7025601 100644 --- a/src/components/Map/layers/OpenSpaceLayer.js +++ b/src/components/Map/layers/OpenSpaceLayer.js @@ -1,140 +1,102 @@ -import React, { useEffect, useState, useRef } from "react"; +import React, { useEffect, useRef } from "react"; import { Source, Layer } from "react-map-gl"; /** - * Renders OpenSpace (Protected and Recreational OpenSpace) layer - * Data source: https://arcgisserver.digital.mass.gov/arcgisserver/rest/services/AGOL/openspace/FeatureServer/0 - * - * Uses ArcGIS FeatureServer query endpoint to fetch GeoJSON features within current map bounds. + * Renders OpenSpace (Protected and Recreational OpenSpace) layer using Mapbox Vector Tileset + * Tileset ID: ihill.7fjeze3n */ -const OpenSpaceLayer = ({ showOpenSpace, showMunicipalityProfileMap, showProjectTrailsProfile, mapRef, onDataChange }) => { - const [openSpaceData, setOpenSpaceData] = useState(null); - const [bounds, setBounds] = useState(null); - const updateTimeoutRef = useRef(null); - const queryTimeoutRef = useRef(null); - +const OPENSPACE_TILESET_ID = "ihill.7fjeze3n"; +const OPENSPACE_SOURCE_LAYER = "Protected_and_Recreational_Op-98eeg1"; + +const OpenSpaceLayer = ({ showOpenSpace, showMunicipalityProfileMap, showRegionalTrailsProfile, mapRef }) => { + // Use different source IDs for different pages to avoid conflicts + const sourceId = showMunicipalityProfileMap ? "openspace-source-community" : "openspace-source-regional"; + const fillLayerId = showMunicipalityProfileMap ? "openspace-layer-community" : "openspace-layer-regional"; + const outlineLayerId = showMunicipalityProfileMap ? "openspace-outline-community" : "openspace-outline-regional"; + const otherSourceId = showMunicipalityProfileMap ? "openspace-source-regional" : "openspace-source-community"; + const otherFillLayerId = showMunicipalityProfileMap ? "openspace-layer-regional" : "openspace-layer-community"; + const otherOutlineLayerId = showMunicipalityProfileMap ? "openspace-outline-regional" : "openspace-outline-community"; + + // Clean up the other page's source and layers when this component mounts useEffect(() => { - if (!showOpenSpace || (!showMunicipalityProfileMap && !showProjectTrailsProfile) || !mapRef?.current) { - setOpenSpaceData(null); - setBounds(null); - if (onDataChange) onDataChange(null); - return; - } - - const updateLayer = () => { - const map = mapRef.current?.getMap(); - if (!map) return; - - const mapBounds = map.getBounds(); - const sw = mapBounds.getSouthWest(); - const ne = mapBounds.getNorthEast(); - - // Convert lat/lon to Web Mercator (EPSG:3857) for ArcGIS query - const toWebMercator = (lon, lat) => { - const x = lon * 20037508.34 / 180; - let y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180); - y = y * 20037508.34 / 180; - return { x, y }; - }; - - const swMerc = toWebMercator(sw.lng, sw.lat); - const neMerc = toWebMercator(ne.lng, ne.lat); - - const OPENSPACE_SERVICE_URL = "https://arcgisserver.digital.mass.gov/arcgisserver/rest/services/AGOL/openspace/FeatureServer/0"; - const bbox = `${swMerc.x},${swMerc.y},${neMerc.x},${neMerc.y}`; - - // Query GeoJSON from FeatureServer - const url = `${OPENSPACE_SERVICE_URL}/query?where=1=1&geometry=${bbox}&geometryType=esriGeometryEnvelope&inSR=3857&spatialRel=esriSpatialRelIntersects&outFields=*&outSR=4326&f=geojson&returnGeometry=true&maxRecordCount=1000`; - - // Debounce queries - if (queryTimeoutRef.current) { - clearTimeout(queryTimeoutRef.current); + if (!mapRef?.current) return; + + const map = mapRef.current.getMap(); + if (!map) return; + + const cleanupOtherPage = () => { + // Wait for style to load before cleaning up + if (!map.isStyleLoaded()) { + map.once('styledata', cleanupOtherPage); + return; } - queryTimeoutRef.current = setTimeout(async () => { - try { - const response = await fetch(url); - const data = await response.json(); - - if (data.features && data.features.length > 0) { - const featureCollection = { - type: "FeatureCollection", - features: data.features - }; - setOpenSpaceData(featureCollection); - setBounds([ - [sw.lng, sw.lat], - [ne.lng, ne.lat] - ]); - if (onDataChange) onDataChange(featureCollection); - } else { - setOpenSpaceData(null); - if (onDataChange) onDataChange(null); - } - } catch (error) { - console.error("Error fetching OpenSpace data:", error); - setOpenSpaceData(null); + // Remove the other page's layers and source if they exist + try { + // Remove other page's layers first + if (map.getLayer(otherFillLayerId)) { + map.removeLayer(otherFillLayerId); } - }, 300); - }; - - // Initial update - updateLayer(); - - // Update on map move (with debounce) - const map = mapRef.current?.getMap(); - if (map) { - const handleMoveEnd = () => { - if (updateTimeoutRef.current) { - clearTimeout(updateTimeoutRef.current); + if (map.getLayer(otherOutlineLayerId)) { + map.removeLayer(otherOutlineLayerId); } - updateTimeoutRef.current = setTimeout(updateLayer, 300); - }; - - map.on('moveend', handleMoveEnd); - map.on('zoomend', handleMoveEnd); - - return () => { - map.off('moveend', handleMoveEnd); - map.off('zoomend', handleMoveEnd); - if (updateTimeoutRef.current) { - clearTimeout(updateTimeoutRef.current); - } - if (queryTimeoutRef.current) { - clearTimeout(queryTimeoutRef.current); + + // Remove other page's source + if (map.getSource(otherSourceId)) { + map.removeSource(otherSourceId); } - }; - } - }, [showOpenSpace, showMunicipalityProfileMap, showProjectTrailsProfile, mapRef, onDataChange]); + } catch (err) { + // Source or layer might not exist, which is fine + } + }; - // Handle hover events - removed, will be handled in parent component's onMouseMove + // Small delay to ensure current page's layers are added first + const timeoutId = setTimeout(cleanupOtherPage, 100); + + return () => { + clearTimeout(timeoutId); + if (map && map.off) { + map.off('styledata', cleanupOtherPage); + } + }; + }, [mapRef, otherSourceId, otherFillLayerId, otherOutlineLayerId]); - if (!showOpenSpace || (!showMunicipalityProfileMap && !showProjectTrailsProfile) || !openSpaceData) { + if (!showOpenSpace || (!showMunicipalityProfileMap && !showRegionalTrailsProfile)) { return null; } + // Mapbox tileset URL format: mapbox://tileset-id + const tilesetUrl = `mapbox://${OPENSPACE_TILESET_ID}`; + return ( + {/* OpenSpace polygon fill layer */} + {/* OpenSpace outline line layer */} @@ -143,4 +105,3 @@ const OpenSpaceLayer = ({ showOpenSpace, showMunicipalityProfileMap, showProject }; export default OpenSpaceLayer; - diff --git a/src/components/Map/layers/OriginalTrailsFilterLayers.js b/src/components/Map/layers/OriginalTrailsFilterLayers.js index 34f542a..e588ba3 100644 --- a/src/components/Map/layers/OriginalTrailsFilterLayers.js +++ b/src/components/Map/layers/OriginalTrailsFilterLayers.js @@ -4,7 +4,7 @@ import { Layer } from "react-map-gl"; /** * Renders vector tile layers for original trails filters */ -const OriginalTrailsFilterLayers = ({ trailLayers, proposedLayers, existingTrails, proposedTrails }) => { +const OriginalTrailsFilterLayers = ({ trailLayers, proposedLayers, existingTrails, proposedTrails, hoveredTrailId }) => { const filterLayers = []; const allLayers = [...trailLayers, ...proposedLayers]; @@ -13,16 +13,38 @@ const OriginalTrailsFilterLayers = ({ trailLayers, proposedLayers, existingTrail const addLayer = layerSet.find((l) => l.id === layer); if (addLayer) { filterLayers.push( - + + + {/* Hover layer: thicker line when hovering */} + + ); } }); diff --git a/src/components/Map/layers/OtherRegionalTrailsLayer.js b/src/components/Map/layers/OtherRegionalTrailsLayer.js new file mode 100644 index 0000000..acbfaa4 --- /dev/null +++ b/src/components/Map/layers/OtherRegionalTrailsLayer.js @@ -0,0 +1,708 @@ +import React, { useEffect, useState, useRef, useMemo } from "react"; +import { Source, Layer } from "react-map-gl"; + +/** + * Generates a color palette for different reg_name values + * Returns a consistent color for each unique reg_name + */ +const generateColorPalette = (regNames) => { + const colors = [ + "#FF6B35", "#4ECDC4", "#45B7D1", "#FFA07A", "#98D8C8", + "#F7DC6F", "#BB8FCE", "#85C1E2", "#F8B739", "#52BE80", + "#EC7063", "#5DADE2", "#F1948A", "#58D68D", "#F4D03F", + "#AF7AC5", "#7FB3D3", "#F5B041", "#82E0AA", "#F39C12", + "#E74C3C", "#3498DB", "#E67E22", "#1ABC9C", "#9B59B6", + "#34495E", "#16A085", "#27AE60", "#2980B9", "#8E44AD" + ]; + + const palette = {}; + regNames.forEach((name, index) => { + if (name && name.trim() !== "") { + palette[name] = colors[index % colors.length]; + } + }); + + return palette; +}; + +/** + * Renders Other Regional Trails layer using ArcGIS FeatureServer for data + * Data source: https://services.arcgis.com/c5WwApDsDjRhIVkH/arcgis/rest/services/export_other_trails/FeatureServer + * + * Uses FeatureServer queries to fetch GeoJSON data for rendering and data extraction (reg_names, metrics). + * Renders trails as GeoJSON to support filtering by selectedRegNames and color coding. + * Supports color coding by reg_name attribute when useColorCoding is true. + */ +const OtherRegionalTrailsLayer = ({ + showTrailsRegNameSync, + showMunicipalityProfileMap, + showRegionalTrailsProfile, + mapRef, + useColorCoding = false, + onRegNamesChange = null, + selectedRegNames = [], // Array of selected reg_names to display + onTrailsDataChange = null, // Callback to pass trail data to parent + hoveredTrail = null, // Hovered trail object with featureId + clickedTrail = null // Clicked trail object with featureId +}) => { + const [trailsData, setTrailsData] = useState(null); + const updateTimeoutRef = useRef(null); + const queryTimeoutRef = useRef(null); + const accumulatedTrailsRef = useRef(new Map()); // Store trails by feature ID to avoid duplicates + + // Determine if layer should be shown + const shouldShow = showTrailsRegNameSync && (showMunicipalityProfileMap || showRegionalTrailsProfile); + + // ArcGIS token for authentication + const ARCGIS_TOKEN = "AAPTxy8BH1VEsoebNVZXo8HurFEryhzMUuo6HFsZYNxtvAILm5qQYklTujgW8rejiSVEA_kTru4Y7QuNe5-QWMtEpK-_L9TLSHlHV4h_oeYUONaR40fn8mVNBCPvWBSuheHtx9FPMu5xWNxz4gqnZ-TPnErmJVpoN7thS4Zj2QiLg12SqmtHyaMnnYJH5AwdRA1VAFZLZrfwWTLw4zLogHqqonCw58CKKRJS4rqd-UgsAO8.AT1_U0702ST1"; + + // MapServer URL for tile display (tiles only, doesn't support queries) + const MAP_SERVER_URL = "https://services.arcgis.com/c5WwApDsDjRhIVkH/arcgis/rest/services/export_other_trails_tiles/MapServer"; + + // FeatureServer URL for data extraction (supports queries) + const FEATURE_SERVER_URL = "https://services.arcgis.com/c5WwApDsDjRhIVkH/arcgis/rest/services/export_other_trails/FeatureServer/0"; + + // Initial query to get all reg_names for the project list (runs once) + useEffect(() => { + if (!shouldShow || !onRegNamesChange) { + return; + } + + // Query for all reg_names - fetch all unique reg_names without geometry filter + const fetchAllRegNames = async () => { + try { + // Try querying without geometry first (faster and gets all reg_names) + // If that fails, fall back to geometry-based query with large bounds + let url = `${FEATURE_SERVER_URL}/query?where=reg_name IS NOT NULL&outFields=reg_name&returnGeometry=false&returnDistinctValues=true&f=geojson&maxRecordCount=10000&token=${ARCGIS_TOKEN}`; + + let response = await fetch(url); + let data = await response.json(); + + // If returnDistinctValues doesn't work, try without it + if (data.error || !data.features || data.features.length === 0) { + // Fallback: query with large bounds + const bbox = "-180,-90,180,90"; + url = `${FEATURE_SERVER_URL}/query?where=reg_name IS NOT NULL&geometry=${bbox}&geometryType=esriGeometryEnvelope&inSR=4326&spatialRel=esriSpatialRelIntersects&outFields=reg_name&returnGeometry=false&f=geojson&maxRecordCount=10000&token=${ARCGIS_TOKEN}`; + response = await fetch(url); + data = await response.json(); + } + + if (data.error) { + console.error("Error fetching reg_names from FeatureServer:", data.error); + return; + } + + if (data.features && data.features.length > 0) { + const regNames = new Set(); + data.features.forEach(feature => { + const regName = feature.properties?.reg_name; + if (regName && regName.trim() !== "") { + regNames.add(regName); + } + }); + const uniqueRegNames = Array.from(regNames).sort(); + onRegNamesChange(uniqueRegNames); + } + } catch (error) { + console.error("Error fetching all reg_names from FeatureServer:", error); + } + }; + + fetchAllRegNames(); + }, [shouldShow, onRegNamesChange]); + + // Note: reg_names list is populated by the initial query above + // trailsData is only used for rendering and metrics, not for populating the project list + + // Generate color palette from current data when useColorCoding is enabled + const effectiveColorPalette = useMemo(() => { + if (!useColorCoding) { + return {}; + } + + // Generate from current data + if (!trailsData || !trailsData.features) { + return {}; + } + + const regNames = new Set(); + trailsData.features.forEach(feature => { + const regName = feature.properties?.reg_name; + if (regName && regName.trim() !== "") { + regNames.add(regName); + } + }); + + const uniqueRegNames = Array.from(regNames).sort(); + return generateColorPalette(uniqueRegNames); + }, [useColorCoding, trailsData]); + + useEffect(() => { + if (!shouldShow || !mapRef?.current) { + setTrailsData(null); + accumulatedTrailsRef.current.clear(); // Clear accumulated data when layer is hidden + return; + } + + const updateLayer = () => { + const map = mapRef.current?.getMap(); + if (!map) return; + + let url; + + // If projects are selected, query all trails for those projects regardless of map bounds + if (selectedRegNames && selectedRegNames.length > 0) { + // Build WHERE clause to filter by selected reg_names + // Escape single quotes in reg_names and build OR conditions + const whereConditions = selectedRegNames.map(regName => { + const escapedName = (regName || "").replace(/'/g, "''"); // Escape single quotes for SQL + return `reg_name = '${escapedName}'`; + }).join(' OR '); + + const whereClause = `(${whereConditions})`; + + // Query all trails for selected projects (no geometry filter) + url = `${FEATURE_SERVER_URL}/query?where=${encodeURIComponent(whereClause)}&outFields=*&outSR=4326&f=geojson&returnGeometry=true&maxRecordCount=10000&token=${ARCGIS_TOKEN}`; + } else { + // No projects selected - use map bounds query for initial data loading + const zoom = map.getZoom(); + const mapBounds = map.getBounds(); + const sw = mapBounds.getSouthWest(); + const ne = mapBounds.getNorthEast(); + + // Expand bounds at lower zoom levels to ensure we capture more trails + // At zoom < 10, expand by 50%, at zoom < 8, expand by 100% + const expansionFactor = zoom < 8 ? 1.0 : zoom < 10 ? 0.5 : 0; + const latRange = ne.lat - sw.lat; + const lngRange = ne.lng - sw.lng; + + const expandedSw = { + lat: sw.lat - (latRange * expansionFactor), + lng: sw.lng - (lngRange * expansionFactor) + }; + const expandedNe = { + lat: ne.lat + (latRange * expansionFactor), + lng: ne.lng + (lngRange * expansionFactor) + }; + + // Use lat/lng directly (WGS84) for FeatureServer query + // Format: xmin,ymin,xmax,ymax (lng,lat,lng,lat) - ensure proper order + const xmin = Math.min(expandedSw.lng, expandedNe.lng); + const ymin = Math.min(expandedSw.lat, expandedNe.lat); + const xmax = Math.max(expandedSw.lng, expandedNe.lng); + const ymax = Math.max(expandedSw.lat, expandedNe.lat); + const bbox = `${xmin},${ymin},${xmax},${ymax}`; + + // Query GeoJSON from FeatureServer with token authentication (for data extraction) + url = `${FEATURE_SERVER_URL}/query?where=1=1&geometry=${bbox}&geometryType=esriGeometryEnvelope&inSR=4326&spatialRel=esriSpatialRelIntersects&outFields=*&outSR=4326&f=geojson&returnGeometry=true&maxRecordCount=2000&token=${ARCGIS_TOKEN}`; + } + + // Debounce queries + if (queryTimeoutRef.current) { + clearTimeout(queryTimeoutRef.current); + } + + queryTimeoutRef.current = setTimeout(async () => { + try { + const response = await fetch(url); + + if (!response.ok) { + const errorText = await response.text(); + console.error(`FeatureServer query failed (${response.status}):`, errorText); + // Don't clear accumulated data on error + if (accumulatedTrailsRef.current.size === 0) { + setTrailsData(null); + } + return; + } + + const data = await response.json(); + + if (data.error) { + console.error("FeatureServer error:", data.error); + // Don't clear accumulated data on error + if (accumulatedTrailsRef.current.size === 0) { + setTrailsData(null); + } + return; + } + + if (data.features && data.features.length > 0) { + // If querying by selectedRegNames, replace data entirely (don't accumulate) + // If querying by bounds, accumulate data for panning + if (selectedRegNames && selectedRegNames.length > 0) { + // Replace data for selected projects + const featureCollection = { + type: "FeatureCollection", + features: data.features + }; + accumulatedTrailsRef.current.clear(); + data.features.forEach(feature => { + const featureId = feature.properties?.OBJECTID || + feature.properties?.objectid || + feature.id || + JSON.stringify(feature.geometry); + accumulatedTrailsRef.current.set(featureId, feature); + }); + setTrailsData(featureCollection); + + // Notify parent component of trail data changes + if (onTrailsDataChange) { + onTrailsDataChange(featureCollection); + } + } else { + // Accumulate data for bounds-based queries (when panning) + data.features.forEach(feature => { + const featureId = feature.properties?.OBJECTID || + feature.properties?.objectid || + feature.id || + JSON.stringify(feature.geometry); + accumulatedTrailsRef.current.set(featureId, feature); + }); + + // Convert accumulated features back to FeatureCollection + const allFeatures = Array.from(accumulatedTrailsRef.current.values()); + const featureCollection = { + type: "FeatureCollection", + features: allFeatures + }; + setTrailsData(featureCollection); + + // Notify parent component of trail data changes + if (onTrailsDataChange) { + onTrailsDataChange(featureCollection); + } + } + } else { + // No features returned + if (selectedRegNames && selectedRegNames.length > 0) { + // For selected projects, clear data if no results + accumulatedTrailsRef.current.clear(); + setTrailsData(null); + if (onTrailsDataChange) { + onTrailsDataChange(null); + } + } else if (accumulatedTrailsRef.current.size === 0) { + // Only set to null if we have no accumulated data + setTrailsData(null); + } + } + } catch (error) { + console.error("Error fetching export_other_trails FeatureServer data:", error); + // Don't clear accumulated data on error + if (accumulatedTrailsRef.current.size === 0) { + setTrailsData(null); + } + } + }, 300); + }; + + // Clear accumulated data when selectedRegNames changes + accumulatedTrailsRef.current.clear(); + + // Initial update + updateLayer(); + + // Only update on map move if no projects are selected (when using bounds-based query) + // If projects are selected, we've already fetched all trails, so no need to update on move + const map = mapRef.current?.getMap(); + if (map && (!selectedRegNames || selectedRegNames.length === 0)) { + const handleMoveEnd = () => { + if (updateTimeoutRef.current) { + clearTimeout(updateTimeoutRef.current); + } + updateTimeoutRef.current = setTimeout(updateLayer, 300); + }; + + map.on('moveend', handleMoveEnd); + map.on('zoomend', handleMoveEnd); + + return () => { + map.off('moveend', handleMoveEnd); + map.off('zoomend', handleMoveEnd); + if (updateTimeoutRef.current) { + clearTimeout(updateTimeoutRef.current); + } + if (queryTimeoutRef.current) { + clearTimeout(queryTimeoutRef.current); + } + }; + } else { + // Cleanup timeouts if no map move listeners + return () => { + if (updateTimeoutRef.current) { + clearTimeout(updateTimeoutRef.current); + } + if (queryTimeoutRef.current) { + clearTimeout(queryTimeoutRef.current); + } + }; + } + }, [shouldShow, mapRef, selectedRegNames]); + + // Render GeoJSON from MapServer queries (data extraction happens separately) + // trailsData is needed for reg_names extraction, metrics, and rendering + if (!shouldShow) { + return null; + } + + // If selectedRegNames is empty array, don't show any trails + if (selectedRegNames && selectedRegNames.length === 0) { + return null; + } + + // Need trailsData for rendering + if (!trailsData || !trailsData.features) { + return null; + } + + // If using color coding, create separate layers for each reg_name + if (useColorCoding && Object.keys(effectiveColorPalette).length > 0) { + // Filter to only show selected reg_names (if provided) + // If selectedRegNames is empty, don't show any trails + const regNamesToShow = selectedRegNames.length > 0 + ? Object.keys(effectiveColorPalette).filter(regName => { + // Normalize for comparison (trim and lowercase) + const normalizedRegName = (regName || "").trim().toLowerCase(); + return selectedRegNames.some(selected => { + const normalizedSelected = (selected || "").trim().toLowerCase(); + return normalizedRegName === normalizedSelected; + }); + }) + : []; + + if (regNamesToShow.length === 0) { + return null; // No selected projects, don't show any trails + } + + // For color coding, use GeoJSON from MapServer queries since raster tiles don't support filtering + // Filter trailsData to only show selected reg_names + if (!trailsData || !trailsData.features) { + return null; + } + + const filteredTrailsData = { + type: "FeatureCollection", + features: trailsData.features.filter(feature => { + const featureRegName = (feature.properties?.reg_name || "").trim(); + const segType = feature.properties?.seg_type; + return regNamesToShow.some(regName => { + const normalizedRegName = (regName || "").trim().toLowerCase(); + const normalizedFeatureRegName = featureRegName.toLowerCase(); + return normalizedFeatureRegName === normalizedRegName && segType !== 9 && segType !== "9"; + }); + }) + }; + + const filteredGapsData = { + type: "FeatureCollection", + features: trailsData.features.filter(feature => { + const featureRegName = (feature.properties?.reg_name || "").trim(); + const segType = feature.properties?.seg_type; + return regNamesToShow.some(regName => { + const normalizedRegName = (regName || "").trim().toLowerCase(); + const normalizedFeatureRegName = featureRegName.toLowerCase(); + return normalizedFeatureRegName === normalizedRegName && (segType === 9 || segType === "9"); + }); + }) + }; + + return ( + <> + {/* Render regular trails with color coding */} + {regNamesToShow.map((regName) => { + const color = effectiveColorPalette[regName]; + if (!color) return null; + + const regNameTrails = filteredTrailsData.features.filter(f => { + const fRegName = (f.properties?.reg_name || "").trim().toLowerCase(); + return fRegName === regName.trim().toLowerCase(); + }); + + if (regNameTrails.length === 0) return null; + + return ( + + + + ); + })} + + {/* Render gaps in red */} + {filteredGapsData.features.length > 0 && ( + + + + )} + + ); + } + + // Default: Use GeoJSON from MapServer queries for filtering support + // Get hovered and clicked feature IDs + const hoveredFeatureId = hoveredTrail?.featureId; + const clickedFeatureId = clickedTrail?.featureId; + + // Filter trailsData based on selectedRegNames if provided + let filteredTrailsData = trailsData; + let filteredGapsData = null; + + if (selectedRegNames && selectedRegNames.length > 0 && trailsData && trailsData.features) { + const regularTrails = trailsData.features.filter(feature => { + const regName = (feature.properties?.reg_name || "").trim().toLowerCase(); + const segType = feature.properties?.seg_type; + return selectedRegNames.some(selected => { + const normalizedSelected = (selected || "").trim().toLowerCase(); + return normalizedSelected === regName && segType !== 9 && segType !== "9"; + }); + }); + + const gaps = trailsData.features.filter(feature => { + const regName = (feature.properties?.reg_name || "").trim().toLowerCase(); + const segType = feature.properties?.seg_type; + return selectedRegNames.some(selected => { + const normalizedSelected = (selected || "").trim().toLowerCase(); + return normalizedSelected === regName && (segType === 9 || segType === "9"); + }); + }); + + filteredTrailsData = { + type: "FeatureCollection", + features: regularTrails + }; + + if (gaps.length > 0) { + filteredGapsData = { + type: "FeatureCollection", + features: gaps + }; + } + } else if (trailsData && trailsData.features) { + // No filtering - show all trails + filteredTrailsData = { + type: "FeatureCollection", + features: trailsData.features.filter(f => { + const segType = f.properties?.seg_type; + return segType !== 9 && segType !== "9"; + }) + }; + + const gaps = trailsData.features.filter(f => { + const segType = f.properties?.seg_type; + return segType === 9 || segType === "9"; + }); + + if (gaps.length > 0) { + filteredGapsData = { + type: "FeatureCollection", + features: gaps + }; + } + } + + if (!filteredTrailsData || !filteredTrailsData.features || filteredTrailsData.features.length === 0) { + return null; + } + + // Build hover filters + const regularTrailsHoverFilter = hoveredFeatureId !== null && hoveredFeatureId !== undefined + ? [ + "==", + ["coalesce", ["get", "OBJECTID"], ["get", "objectid"], ["get", "id"], -1], + hoveredFeatureId + ] + : ["==", ["get", "OBJECTID"], -1]; + + const gapsHoverFilter = hoveredFeatureId !== null && hoveredFeatureId !== undefined + ? [ + "==", + ["coalesce", ["get", "OBJECTID"], ["get", "objectid"], ["get", "id"], -1], + hoveredFeatureId + ] + : ["==", ["get", "OBJECTID"], -1]; + + // fac_stat can be number 1 or string "1" from ArcGIS - check both for existing (blue) + const isExistingTrail = ["any", ["==", ["get", "fac_stat"], 1], ["==", ["get", "fac_stat"], "1"]]; + + const regularTrailsClickFilter = clickedFeatureId !== null && clickedFeatureId !== undefined + ? [ + "==", + ["coalesce", ["get", "OBJECTID"], ["get", "objectid"], ["get", "id"], -1], + clickedFeatureId + ] + : ["==", ["get", "OBJECTID"], -1]; + + const gapsClickFilter = clickedFeatureId !== null && clickedFeatureId !== undefined + ? [ + "==", + ["coalesce", ["get", "OBJECTID"], ["get", "objectid"], ["get", "id"], -1], + clickedFeatureId + ] + : ["==", ["get", "OBJECTID"], -1]; + + return ( + <> + {/* Regular trails */} + + + {/* Hover layer for regular trails - wider */} + + {/* Click highlight layer for regular trails - thicker when clicked */} + + + + {/* Gaps in red */} + {filteredGapsData && filteredGapsData.features.length > 0 && ( + + + {/* Hover layer for gaps - wider */} + + {/* Click highlight layer for gaps - thicker when clicked */} + + + )} + + ); +}; + +export default OtherRegionalTrailsLayer; diff --git a/src/components/Map/layers/TrailsRegNameSyncLayer.js b/src/components/Map/layers/TrailsRegNameSyncLayer.js deleted file mode 100644 index b07fb5a..0000000 --- a/src/components/Map/layers/TrailsRegNameSyncLayer.js +++ /dev/null @@ -1,442 +0,0 @@ -import React, { useEffect, useState, useRef, useMemo } from "react"; -import { Source, Layer } from "react-map-gl"; - -/** - * Generates a color palette for different reg_name values - * Returns a consistent color for each unique reg_name - */ -const generateColorPalette = (regNames) => { - const colors = [ - "#FF6B35", "#4ECDC4", "#45B7D1", "#FFA07A", "#98D8C8", - "#F7DC6F", "#BB8FCE", "#85C1E2", "#F8B739", "#52BE80", - "#EC7063", "#5DADE2", "#F1948A", "#58D68D", "#F4D03F", - "#AF7AC5", "#7FB3D3", "#F5B041", "#82E0AA", "#F39C12", - "#E74C3C", "#3498DB", "#E67E22", "#1ABC9C", "#9B59B6", - "#34495E", "#16A085", "#27AE60", "#2980B9", "#8E44AD" - ]; - - const palette = {}; - regNames.forEach((name, index) => { - if (name && name.trim() !== "") { - palette[name] = colors[index % colors.length]; - } - }); - - return palette; -}; - -/** - * Renders Trails Reg Name Sync layer from ArcGIS FeatureServer - * Data source: https://services.arcgis.com/c5WwApDsDjRhIVkH/arcgis/rest/services/Trails_Reg_Name_Sync/FeatureServer - * - * Uses FeatureServer query endpoint to fetch GeoJSON features within current map bounds. - * Supports color coding by reg_name attribute when useColorCoding is true. - */ -const TrailsRegNameSyncLayer = ({ - showTrailsRegNameSync, - showMunicipalityProfileMap, - showProjectTrailsProfile, - mapRef, - useColorCoding = false, - onRegNamesChange = null, - colorPalette = null, // External color palette for stable colors - selectedRegNames = [], // Array of selected reg_names to display - onTrailsDataChange = null, // Callback to pass trail data to parent - hoveredTrail = null // Hovered trail object with featureId -}) => { - const [trailsData, setTrailsData] = useState(null); - const updateTimeoutRef = useRef(null); - const queryTimeoutRef = useRef(null); - const accumulatedTrailsRef = useRef(new Map()); // Store trails by feature ID to avoid duplicates - - // Determine if layer should be shown - const shouldShow = showTrailsRegNameSync && (showMunicipalityProfileMap || showProjectTrailsProfile); - - // Extract unique reg_name values and notify parent - useEffect(() => { - if (trailsData && trailsData.features && onRegNamesChange) { - const regNames = new Set(); - trailsData.features.forEach(feature => { - const regName = feature.properties?.reg_name; - if (regName && regName.trim() !== "") { - regNames.add(regName); - } - }); - - const uniqueRegNames = Array.from(regNames).sort(); - onRegNamesChange(uniqueRegNames); - } - }, [trailsData, onRegNamesChange]); - - // Use external color palette if provided, otherwise generate one - const effectiveColorPalette = useMemo(() => { - if (!useColorCoding) { - return {}; - } - - // If external palette is provided, use it - if (colorPalette && Object.keys(colorPalette).length > 0) { - return colorPalette; - } - - // Otherwise, generate from current data (fallback) - if (!trailsData || !trailsData.features) { - return {}; - } - - const regNames = new Set(); - trailsData.features.forEach(feature => { - const regName = feature.properties?.reg_name; - if (regName && regName.trim() !== "") { - regNames.add(regName); - } - }); - - const uniqueRegNames = Array.from(regNames).sort(); - return generateColorPalette(uniqueRegNames); - }, [useColorCoding, colorPalette, trailsData]); - - useEffect(() => { - if (!shouldShow || !mapRef?.current) { - setTrailsData(null); - accumulatedTrailsRef.current.clear(); // Clear accumulated data when layer is hidden - return; - } - - const updateLayer = () => { - const map = mapRef.current?.getMap(); - if (!map) return; - - const zoom = map.getZoom(); - const mapBounds = map.getBounds(); - const sw = mapBounds.getSouthWest(); - const ne = mapBounds.getNorthEast(); - - // Expand bounds at lower zoom levels to ensure we capture more trails - // At zoom < 10, expand by 50%, at zoom < 8, expand by 100% - const expansionFactor = zoom < 8 ? 1.0 : zoom < 10 ? 0.5 : 0; - const latRange = ne.lat - sw.lat; - const lngRange = ne.lng - sw.lng; - - const expandedSw = { - lat: sw.lat - (latRange * expansionFactor), - lng: sw.lng - (lngRange * expansionFactor) - }; - const expandedNe = { - lat: ne.lat + (latRange * expansionFactor), - lng: ne.lng + (lngRange * expansionFactor) - }; - - // Convert lat/lon to Web Mercator (EPSG:3857) for ArcGIS query - const toWebMercator = (lon, lat) => { - const x = lon * 20037508.34 / 180; - let y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180); - y = y * 20037508.34 / 180; - return { x, y }; - }; - - const swMerc = toWebMercator(expandedSw.lng, expandedSw.lat); - const neMerc = toWebMercator(expandedNe.lng, expandedNe.lat); - - const TRAILS_SERVICE_URL = "https://services.arcgis.com/c5WwApDsDjRhIVkH/arcgis/rest/services/Trails_Reg_Name_Sync/FeatureServer/0"; - const bbox = `${swMerc.x},${swMerc.y},${neMerc.x},${neMerc.y}`; - - // ArcGIS token for authentication - const ARCGIS_TOKEN = "AAPTxy8BH1VEsoebNVZXo8HurFEryhzMUuo6HFsZYNxtvAJokki38mbvq7ULTwGi9aIiHg4Ov6mdqMd5YhY2eBLginTWOW2s0AQjeI7Ykqag6M-aN9ebZDjDH92AC2SZZXZMAva-9dhU3So7ctlz8NNnI5atBAQ3zzUBhRN7PBfx6N9e-Dr6ye-m_8BAjmSw2KJDlOpeyXL4Zzk31HB6h95KMEUz0KeUmSeCEw6OsOp3Zeg.AT1_U0702ST1"; - - // Query GeoJSON from FeatureServer with token authentication - const url = `${TRAILS_SERVICE_URL}/query?where=1=1&geometry=${bbox}&geometryType=esriGeometryEnvelope&inSR=3857&spatialRel=esriSpatialRelIntersects&outFields=*&outSR=4326&f=geojson&returnGeometry=true&maxRecordCount=2000&token=${ARCGIS_TOKEN}`; - - // Debounce queries - if (queryTimeoutRef.current) { - clearTimeout(queryTimeoutRef.current); - } - - queryTimeoutRef.current = setTimeout(async () => { - try { - const response = await fetch(url); - const data = await response.json(); - - if (data.features && data.features.length > 0) { - // Add new features to accumulated data, using OBJECTID or a unique identifier - data.features.forEach(feature => { - const featureId = feature.properties?.OBJECTID || - feature.properties?.objectid || - feature.id || - JSON.stringify(feature.geometry); - accumulatedTrailsRef.current.set(featureId, feature); - }); - - // Convert accumulated features back to FeatureCollection - const allFeatures = Array.from(accumulatedTrailsRef.current.values()); - const featureCollection = { - type: "FeatureCollection", - features: allFeatures - }; - setTrailsData(featureCollection); - - // Notify parent component of trail data changes - if (onTrailsDataChange) { - onTrailsDataChange(featureCollection); - } - } else if (accumulatedTrailsRef.current.size === 0) { - // Only set to null if we have no accumulated data - setTrailsData(null); - } - } catch (error) { - console.error("Error fetching Trails Reg Name Sync data:", error); - // Don't clear accumulated data on error - if (accumulatedTrailsRef.current.size === 0) { - setTrailsData(null); - } - } - }, 300); - }; - - // Initial update - updateLayer(); - - // Update on map move (with debounce) - const map = mapRef.current?.getMap(); - if (map) { - const handleMoveEnd = () => { - if (updateTimeoutRef.current) { - clearTimeout(updateTimeoutRef.current); - } - updateTimeoutRef.current = setTimeout(updateLayer, 300); - }; - - map.on('moveend', handleMoveEnd); - map.on('zoomend', handleMoveEnd); - - return () => { - map.off('moveend', handleMoveEnd); - map.off('zoomend', handleMoveEnd); - if (updateTimeoutRef.current) { - clearTimeout(updateTimeoutRef.current); - } - if (queryTimeoutRef.current) { - clearTimeout(queryTimeoutRef.current); - } - }; - } - }, [shouldShow, mapRef]); - - if (!shouldShow || !trailsData) { - return null; - } - - // If using color coding, create separate layers for each reg_name - if (useColorCoding && Object.keys(effectiveColorPalette).length > 0) { - // Filter to only show selected reg_names (if provided) - // If selectedRegNames is empty, don't show any trails - const regNamesToShow = selectedRegNames.length > 0 - ? Object.keys(effectiveColorPalette).filter(regName => selectedRegNames.includes(regName)) - : []; - - if (regNamesToShow.length === 0) { - return null; // No selected projects, don't show any trails - } - - return ( - <> - {/* Render regular trails first */} - {regNamesToShow.map((regName) => { - const color = effectiveColorPalette[regName]; - if (!color) return null; - - const filteredFeatures = trailsData.features.filter( - feature => { - const featureRegName = (feature.properties?.reg_name || "").trim(); - const segType = feature.properties?.seg_type; - // Exclude gaps (seg_type === 9) from regular trail layer - return featureRegName === regName.trim() && segType !== 9 && segType !== "9"; - } - ); - - if (filteredFeatures.length === 0) return null; - - return ( - - - - ); - })} - - {/* Render gaps in red on top of regular trails */} - {regNamesToShow.map((regName) => { - const filteredGapFeatures = trailsData.features.filter( - feature => { - const featureRegName = (feature.properties?.reg_name || "").trim(); - const segType = feature.properties?.seg_type; - // Only include gaps (seg_type === 9) for this reg_name - return featureRegName === regName.trim() && (segType === 9 || segType === "9"); - } - ); - - if (filteredGapFeatures.length === 0) return null; - - return ( - - - - ); - })} - - ); - } - - // Default: single layer with single color - // Filter trails based on selectedRegNames if provided - let filteredTrailsData = trailsData; - if (selectedRegNames && selectedRegNames.length > 0) { - filteredTrailsData = { - type: "FeatureCollection", - features: trailsData.features.filter(feature => { - const regName = (feature.properties?.reg_name || "").trim(); - return selectedRegNames.some(selected => selected.trim() === regName); - }) - }; - } else if (selectedRegNames && selectedRegNames.length === 0) { - // If selectedRegNames is empty array, don't show any trails - return null; - } - - // Get hovered feature ID - const hoveredFeatureId = hoveredTrail?.featureId; - - return ( - - {/* Regular trails (excluding gaps) */} - - {/* Hover layer for regular trails - wider */} - - {/* Gaps in red */} - - {/* Hover layer for gaps - wider */} - - - ); -}; - -export default TrailsRegNameSyncLayer; diff --git a/src/components/Map/layers/TransitLandRoutesLayer.js b/src/components/Map/layers/TransitLandRoutesLayer.js index ba83e7f..094fe5a 100644 --- a/src/components/Map/layers/TransitLandRoutesLayer.js +++ b/src/components/Map/layers/TransitLandRoutesLayer.js @@ -29,7 +29,7 @@ const TransitLandRoutesLayer = ({ id="transit-land-routes" type="line" source-layer="routes" - interactive={false} + interactive={true} paint={{ "line-color": [ "case", diff --git a/src/components/Map/tooltip/BlueBikeStationPopupContent.js b/src/components/Map/tooltip/BlueBikeStationPopupContent.js new file mode 100644 index 0000000..de8f188 --- /dev/null +++ b/src/components/Map/tooltip/BlueBikeStationPopupContent.js @@ -0,0 +1,61 @@ +import React from "react"; +import styled from "styled-components"; + +const BlueBikePopupContainer = styled.div` + min-width: 200px; + color: #2774bd; + font-size: 12px; + word-wrap: break-word; + overflow-wrap: break-word; +`; + +const BlueBikePopupTitle = styled.div` + font-weight: 600; + margin-bottom: 6px; + word-wrap: break-word; + overflow-wrap: break-word; +`; + +const BlueBikePopupName = styled.div` + margin-bottom: 4px; + font-weight: 500; + word-wrap: break-word; + overflow-wrap: break-word; +`; + +const BlueBikePopupRow = styled.div` + margin-bottom: 2px; + font-size: 11px; + color: #666; + word-wrap: break-word; + overflow-wrap: break-word; +`; + +const BlueBikeStationPopupContent = ({ properties }) => { + const p = properties || {}; + const stationName = p.Name || p.name || "Unknown Station"; + const district = p.District || p.district || null; + const totalDocks = p.Total_docks ?? p.total_docks ?? null; + const number = p.Number || p.number || null; + const isPublic = + p.Public_ === "Yes" || p.public === "Yes" + ? "Yes" + : p.Public_ === "No" || p.public === "No" + ? "No" + : null; + + return ( + + Blue Bike Station + {stationName} + {district && District: {district}} + {totalDocks != null && ( + Total Docks: {totalDocks} + )} + {number && Station #: {number}} + {isPublic != null && Public: {isPublic}} + + ); +}; + +export default BlueBikeStationPopupContent; diff --git a/src/components/Map/tooltip/CommunityIdentify.js b/src/components/Map/tooltip/CommunityIdentify.js new file mode 100644 index 0000000..6e6c323 --- /dev/null +++ b/src/components/Map/tooltip/CommunityIdentify.js @@ -0,0 +1,230 @@ +import React, { useContext, useState } from "react"; +import { Popup } from "react-map-gl"; +import Button from "react-bootstrap/Button"; +import Carousel from "react-bootstrap/Carousel"; +import editIcon from "../../../assets/icons/edit-icon.svg"; +import { ModalContext } from "../../../App"; +import { getMunicipalityName } from "../utils/municipalityUtils"; + +// Identify popup variant for Community Trails Profile: +// trail name logic matches TrailListWindow: local_name -> reg_name -> prop_name, +// treating "", "Null", " ", and "0" as missing. +const CommunityIdentify = ({ point, identifyResult, handleShowPopup, handleCarousel }) => { + const { toggleEditModal } = useContext(ModalContext); + const [carouselIndex, setCarouselIndex] = useState(0); + + const normalizeCandidate = (value) => { + const v = (value ?? "").toString().trim(); + const lowered = v.toLowerCase(); + // Treat common null-ish values as missing + if ( + v === "" || + v === "0" || + lowered === "null" || + lowered === "" || + lowered === "(null)" || + lowered === "n/a" + ) { + return ""; + } + return v; + }; + + // Check if result is a trail (same as original trails filter) + const isTrailResult = (element) => typeof element.layerId === 'number'; + + const identifyLayer = []; + const identifyTrailName = []; + const identifyMunicipality = []; + const identifyDate = []; + const identifyLength = []; + + identifyResult.forEach((element) => { + identifyLayer.push(element.layerName); + + const attrs = element.attributes || {}; + + // Handle different layer types + let name = ""; + if (element.layerId === 'transit-land-stop' || element.layerName === 'Transit Stop') { + // For transit stops, use Stop Name + name = normalizeCandidate(attrs["Stop Name"] || attrs["stop_name"] || attrs["name"]); + } else if (element.layerId === 'subway-station' || element.layerName === 'T-stop' || element.layerName === 'MBTA Subway Station') { + // For subway stations, use name field + name = normalizeCandidate(attrs["name"]); + } else if (element.layerId === 'blue-bike-station' || element.layerName === 'Blue Bike Station') { + // For blue bike stations, use name field + name = normalizeCandidate(attrs["name"]); + } else if (element.layerId === 'municipality' || element.layerName === 'Municipality') { + // For municipalities, use name field + name = normalizeCandidate(attrs["name"] || attrs["town"] || attrs["NAME"]); + } else if (isTrailResult(element)) { + // For trails: same as Identify.js - Local Name -> Regional Name -> Property Name (or snake_case equivalents) + const localName = normalizeCandidate(attrs["Local Name"] || attrs["local_name"]); + const regionalName = normalizeCandidate(attrs["Regional Name"] || attrs["reg_name"]); + const propertyName = normalizeCandidate(attrs["Property Name"] || attrs["prop_name"]); + name = localName || regionalName || propertyName || ""; + } else { + // For other layers (OpenSpace etc), use standard trail name logic or name field + const localName = normalizeCandidate(attrs["local_name"]); + const regionalName = normalizeCandidate(attrs["reg_name"]); + const propertyName = normalizeCandidate(attrs["prop_name"]); + name = localName || regionalName || propertyName || normalizeCandidate(attrs["name"] || attrs["SITE_NAME"]) || ""; + } + + identifyTrailName.push(name); + + identifyMunicipality.push(getMunicipalityName(attrs["muni_id"] || attrs["Municipal ID"]) ?? ""); + identifyDate.push( + (attrs["Facility Opening Date"] !== undefined && attrs["Facility Opening Date"] !== "Null") + ? attrs["Facility Opening Date"] + : (attrs["open_date"] !== undefined && attrs["open_date"] !== "Null") ? attrs["open_date"] : "" + ); + + const rawLengthFeet = attrs["Facility Length in Feet"] ?? attrs["length_ft"]; + const normalizedLengthFeet = + rawLengthFeet !== undefined && rawLengthFeet !== null && rawLengthFeet !== "Null" && rawLengthFeet !== " " + ? rawLengthFeet + : ""; + identifyLength.push(normalizedLengthFeet); + }); + + const carouselItems = []; + for (let i = 0; i < identifyResult.length; i++) { + const element = identifyResult[i]; + const itemIsTrail = isTrailResult(element); + const attrs = element.attributes || {}; + + if (itemIsTrail) { + // For trails: use same format as original trails filter (Identify.js) + carouselItems.push( + + {(identifyTrailName[i] && Name: {identifyTrailName[i]}) || + (!identifyTrailName[i] && Name: N/A)} + {(identifyLayer[i] && ( + + Type:{" "} + {identifyLayer[i].split(" ")[0] !== "Existing" + ? identifyLayer[i] + : identifyLayer[i].split(" ").slice(1, identifyLayer[i].split(" ").length).join(" ")} + + )) || + (!identifyLayer[i] && Type: N/A)} + {(identifyMunicipality[i] && Municipality: {identifyMunicipality[i]}) || + (!identifyMunicipality[i] && Municipality: N/A)} + {(identifyDate[i] && Opening Date: {identifyDate[i]}) || + (!identifyDate[i] && Opening Date: N/A)} + {(identifyLength[i] && Length: {parseFloat(identifyLength[i]).toFixed(2)} ft) || + (!identifyLength[i] && Length: N/A)} + + ); + } else { + // For non-trails (transit stops, blue bike, T-stops, OpenSpace, etc): show all properties + const allProperties = Object.entries(attrs) + .filter(([key, value]) => { + if (value === null || value === undefined) return false; + const strValue = String(value).trim(); + const lowerValue = strValue.toLowerCase(); + return strValue !== '' && + strValue !== '0' && + lowerValue !== 'null' && + lowerValue !== '' && + lowerValue !== '(null)' && + lowerValue !== 'n/a' && + lowerValue !== 'na'; + }) + .sort(([keyA], [keyB]) => { + const importantFields = ['name', 'Name', 'STATION', 'station', 'Stop Name', 'stop_name', 'SITE_NAME', 'site_name', 'local_name', 'reg_name', 'prop_name', 'town', 'NAME']; + const aImportant = importantFields.indexOf(keyA); + const bImportant = importantFields.indexOf(keyB); + if (aImportant !== -1 && bImportant !== -1) return aImportant - bImportant; + if (aImportant !== -1) return -1; + if (bImportant !== -1) return 1; + return keyA.localeCompare(keyB); + }); + + carouselItems.push( + +
+ {(identifyLayer[i] && ( +
+ {identifyLayer[i].split(" ")[0] !== "Existing" + ? identifyLayer[i] + : identifyLayer[i].split(" ").slice(1, identifyLayer[i].split(" ").length).join(" ")} +
+ ))} + + {allProperties.length > 0 ? ( +
+ {allProperties.map(([key, value], idx) => { + let displayValue = value; + if (typeof value === 'number') { + if (key.toLowerCase().includes('length') || key.toLowerCase().includes('feet') || key.toLowerCase().includes('ft')) { + displayValue = parseFloat(value).toFixed(2) + ' ft'; + } else if (key.toLowerCase().includes('acre')) { + displayValue = parseFloat(value).toFixed(2) + ' acres'; + } else { + displayValue = value.toString(); + } + } else if (typeof value === 'boolean') { + displayValue = value ? 'Yes' : 'No'; + } else { + displayValue = String(value); + } + + const formattedKey = key + .replace(/_/g, ' ') + .replace(/([A-Z])/g, ' $1') + .replace(/^./, str => str.toUpperCase()) + .trim(); + + return ( +
+ {formattedKey}:{' '} + {displayValue} +
+ ); + })} +
+ ) : ( +
No properties available
+ )} +
+
+ ); + } + } + + function handleSelect(event) { + setCarouselIndex(event); + handleCarousel(event); + } + + return ( + handleShowPopup(false)}> + 1} + activeIndex={carouselIndex} + onSelect={handleSelect} + > + {carouselItems} + + {/* Edit button only for trail tooltips */} + {identifyResult.length > 0 && isTrailResult(identifyResult[carouselIndex]) && ( + + )} + + ); +}; + +export default CommunityIdentify; diff --git a/src/components/Map/tooltip/EnvironmentalJusticePopupContent.js b/src/components/Map/tooltip/EnvironmentalJusticePopupContent.js new file mode 100644 index 0000000..5c17b76 --- /dev/null +++ b/src/components/Map/tooltip/EnvironmentalJusticePopupContent.js @@ -0,0 +1,78 @@ +import React from "react"; +import styled from "styled-components"; + +const EJPopupContainer = styled.div` + min-width: 200px; + max-width: 300px; + color: #2774bd; + font-size: 12px; + word-wrap: break-word; + overflow-wrap: break-word; +`; + +const EJPopupTitle = styled.div` + font-weight: 600; + margin-bottom: 8px; + font-size: 14px; + word-wrap: break-word; + overflow-wrap: break-word; +`; + +const EJPopupRow = styled.div` + margin-bottom: 4px; + word-wrap: break-word; + overflow-wrap: break-word; + font-size: ${(props) => (props.$muted ? "11px" : "inherit")}; + color: ${(props) => (props.$muted ? "#666" : "inherit")}; +`; + +// Supports both UPPER_SNAKE_CASE (RegionalTrailsProfile) and PascalCase (CommunityTrailsProfile) property names +const EnvironmentalJusticePopupContent = ({ properties }) => { + const p = properties || {}; + const area = p.GEOGRAPHICAREANAME || p.Geographic_Area_Name; + const municipality = p.MUNICIPALITY || p.Municipality; + const ejCritDesc = p.EJ_CRIT_DESC || p.EJ_Crit_Desc; + const ej = p.EJ || p.Ej; + const totalPop = p.TOTAL_POP; + const pctMinority = p.PCT_MINORITY; + const limEnghHPct = p.LIMENGHHPCT; + const bgMhhi = p.BG_MHHI; + const geoid = p.GEOID; + const hasData = area || municipality || ejCritDesc; + + return ( + + Environmental Justice + {area && ( + Area: {area} + )} + {municipality && ( + Municipality: {municipality} + )} + {ejCritDesc && ( + EJ Criteria: {ejCritDesc} + )} + {ej && ( + EJ Designated: {ej} + )} + {totalPop !== undefined && totalPop !== null && ( + Total Population: {parseFloat(totalPop).toLocaleString()} + )} + {pctMinority !== undefined && pctMinority !== null && ( + Percent Minority: {parseFloat(pctMinority).toFixed(1)}% + )} + {limEnghHPct !== undefined && limEnghHPct !== null && ( + Limited English Households: {parseFloat(limEnghHPct).toFixed(1)}% + )} + {bgMhhi !== undefined && bgMhhi !== null && ( + Median Household Income: ${parseFloat(bgMhhi).toLocaleString()} + )} + {geoid && ( + GEOID: {geoid} + )} + {!hasData && No data available} + + ); +}; + +export default EnvironmentalJusticePopupContent; diff --git a/src/components/Map/Identify.js b/src/components/Map/tooltip/Identify.js similarity index 86% rename from src/components/Map/Identify.js rename to src/components/Map/tooltip/Identify.js index eeb7430..1701d57 100644 --- a/src/components/Map/Identify.js +++ b/src/components/Map/tooltip/Identify.js @@ -2,27 +2,14 @@ import React, { useContext, useState } from "react"; import { Popup } from "react-map-gl"; import Button from "react-bootstrap/Button"; import Carousel from "react-bootstrap/Carousel"; -import editIcon from "../../assets/icons/edit-icon.svg"; -import { ModalContext } from "../../App"; -import muniKeys from "../../data/ma_muni_keys.json"; +import editIcon from "../../../assets/icons/edit-icon.svg"; +import { ModalContext } from "../../../App"; +import { getMunicipalityName } from "../utils/municipalityUtils"; const Identify = ({ point, identifyResult, handleShowPopup, handleCarousel }) => { const { showEditModal, toggleEditModal } = useContext(ModalContext); const [carouselIndex, setCarouselIndex] = useState(0); - // Function to get municipality name by muni_id - const getMunicipalityName = (muniId) => { - if (!muniId || muniId === "Null" || muniId === "") return ""; - - // Handle both string and numeric muni_id - const municipality = muniKeys.find(muni => - muni.muni_id === parseInt(muniId) || - muni.muni_id === muniId || - muni.muni_id.toString() === muniId.toString() - ); - return municipality ? municipality.muni_name : ""; - }; - const identifyLayer = []; const identifyAttributes = []; const identifyTrailName = []; @@ -43,8 +30,7 @@ const Identify = ({ point, identifyResult, handleShowPopup, handleCarousel }) => : "" ); identifyMunicipality.push( - getMunicipalityName(element.attributes["muni_id"] || element.attributes["Municipal ID"]) - + getMunicipalityName(element.attributes["muni_id"] || element.attributes["Municipal ID"]) ?? "" ); identifyDate.push( element.attributes["Facility Opening Date"] !== "Null" ? element.attributes["Facility Opening Date"] : "" diff --git a/src/components/Map/tooltip/OpenSpacePopupContent.js b/src/components/Map/tooltip/OpenSpacePopupContent.js new file mode 100644 index 0000000..14f6075 --- /dev/null +++ b/src/components/Map/tooltip/OpenSpacePopupContent.js @@ -0,0 +1,58 @@ +import React from "react"; +import styled from "styled-components"; + +const OpenSpacePopupContainer = styled.div` + min-width: 200px; + max-width: 300px; + color: #2774bd; + font-size: 12px; + word-wrap: break-word; + overflow-wrap: break-word; +`; + +const OpenSpacePopupTitle = styled.div` + font-weight: 600; + margin-bottom: 6px; + word-wrap: break-word; + overflow-wrap: break-word; +`; + +const OpenSpacePopupRow = styled.div` + margin-bottom: ${(props) => (props.$spacing === "sm" ? "2px" : "4px")}; + font-weight: ${(props) => (props.$bold ? 500 : "inherit")}; + word-wrap: break-word; + overflow-wrap: break-word; +`; + +const OpenSpacePopupContent = ({ properties }) => { + const p = properties || {}; + + return ( + + OpenSpace + {p.SITE_NAME && ( + {p.SITE_NAME} + )} + {p.FEE_OWNER && ( + Owner: {p.FEE_OWNER} + )} + {p.OWNER_TYPE && ( + Owner Type: {p.OWNER_TYPE} + )} + {p.PRIM_PURP && ( + Primary Purpose: {p.PRIM_PURP} + )} + {p.PUB_ACCESS && ( + Public Access: {p.PUB_ACCESS} + )} + {p.GIS_ACRES !== null && p.GIS_ACRES !== undefined && ( + Acres: {parseFloat(p.GIS_ACRES).toFixed(2)} + )} + {!p.SITE_NAME && !p.FEE_OWNER && ( + No data available + )} + + ); +}; + +export default OpenSpacePopupContent; diff --git a/src/components/Map/tooltip/TrailPopupContent.js b/src/components/Map/tooltip/TrailPopupContent.js new file mode 100644 index 0000000..cda46eb --- /dev/null +++ b/src/components/Map/tooltip/TrailPopupContent.js @@ -0,0 +1,91 @@ +import React from "react"; +import styled from "styled-components"; +import { TRAIL_FACILITY_TYPE_LABELS } from "../constants/mapConstants"; +import { getMunicipalityName } from "../utils/municipalityUtils"; + +const TrailPopupContainer = styled.div` + min-width: 200px; + max-width: 300px; + color: #2774bd; + font-size: 12px; + word-wrap: break-word; + overflow-wrap: break-word; +`; + +const TrailPopupTitle = styled.div` + font-weight: 600; + margin-bottom: 8px; + font-size: 14px; + color: #2774bd; + word-wrap: break-word; + overflow-wrap: break-word; +`; + +const TrailPopupRow = styled.div` + margin-bottom: 4px; + word-wrap: break-word; + overflow-wrap: break-word; +`; + +const TrailPopupLink = styled.a` + color: #2774bd; + word-break: break-all; +`; + +const getTrailTypeLabel = (segType, facStat) => + TRAIL_FACILITY_TYPE_LABELS[`${segType},${facStat}`] || null; + +const getStatusLabel = (facStat) => { + if (facStat === 1 || facStat === "1") return "Existing"; + if (facStat === 2 || facStat === "2") return "Design/Construction"; + return "Envisioned"; +}; + +/** + * Reusable trail popup content for Major Trail and Regular Trail click popups. + * @param {object} props + * @param {object} props.properties - Feature properties from the clicked trail + * @param {'grouped_reg_name'|'reg_name'} props.titleKey - Key for the trail name (grouped_reg_name for major trails, reg_name for regular) + */ +const TrailPopupContent = ({ properties, titleKey = "reg_name" }) => { + const p = properties || {}; + const segType = p.seg_type; + const facStat = p.fac_stat; + const trailTypeLabel = getTrailTypeLabel(segType, facStat); + const muniId = p.muni_id || p.MUNI_ID || p.muniId; + const municipalityName = muniId ? getMunicipalityName(muniId) : null; + const title = p[titleKey]; + + return ( + + {title && {title}} + {trailTypeLabel && ( + Type: {trailTypeLabel} + )} + {municipalityName && ( + Municipality: {municipalityName} + )} + {p.steward && ( + Steward: {p.steward} + )} + {p.website && ( + + Website:{" "} + + {p.website.length > 40 ? p.website.substring(0, 40) + "..." : p.website} + + + )} + {p.length_ft && ( + + Length: {(parseFloat(p.length_ft) / 5280).toFixed(2)} miles + + )} + {p.fac_stat != null && ( + Status: {getStatusLabel(p.fac_stat)} + )} + + ); +}; + +export default TrailPopupContent; diff --git a/src/components/Map/utils/arcgisPointQuery.js b/src/components/Map/utils/arcgisPointQuery.js new file mode 100644 index 0000000..eb729dc --- /dev/null +++ b/src/components/Map/utils/arcgisPointQuery.js @@ -0,0 +1,48 @@ +/** + * Query an ArcGIS MapServer/FeatureServer layer at a point (point-in-polygon). + * Useful for raster layers where client doesn't have vector data - query server for attributes at click location. + * + * @param {string} layerUrl - ArcGIS layer URL (e.g. https://.../MapServer/0) + * @param {number} lng - Longitude (EPSG:4326) + * @param {number} lat - Latitude (EPSG:4326) + * @returns {Promise} First feature containing the point, or null + */ +export const queryFeatureAtPoint = async (layerUrl, lng, lat) => { + try { + const toWebMercator = (lon, latVal) => { + const x = lon * 20037508.34 / 180; + const y = Math.log(Math.tan((90 + latVal) * Math.PI / 360)) / (Math.PI / 180); + return { x, y: y * 20037508.34 / 180 }; + }; + + const pointMerc = toWebMercator(lng, lat); + const pointGeometry = { + x: pointMerc.x, + y: pointMerc.y, + spatialReference: { wkid: 3857 } + }; + + const params = new URLSearchParams(); + params.set("where", "1=1"); + params.set("geometry", JSON.stringify(pointGeometry)); + params.set("geometryType", "esriGeometryPoint"); + params.set("inSR", "3857"); + params.set("spatialRel", "esriSpatialRelIntersects"); + params.set("outFields", "*"); + params.set("outSR", "4326"); + params.set("f", "geojson"); + params.set("returnGeometry", "true"); + + const url = `${layerUrl}/query?${params.toString()}`; + const response = await fetch(url); + const data = await response.json(); + + if (data.features && data.features.length > 0) { + return data.features[0]; + } + return null; + } catch (error) { + console.error("Error querying feature at point:", error); + return null; + } +}; diff --git a/src/components/Map/utils/mapQueryUtils.js b/src/components/Map/utils/mapQueryUtils.js new file mode 100644 index 0000000..72013bc --- /dev/null +++ b/src/components/Map/utils/mapQueryUtils.js @@ -0,0 +1,54 @@ +/** + * Get feature(s) from vector layers at a map click point. + * Tries event.features first, then queryRenderedFeatures with center + tolerance points + * (helps catch thin lines not exactly at click). + * + * @param {object} map - Mapbox map instance + * @param {object} event - Map click event with lngLat and optional features + * @param {string[]} layerIds - Layer IDs to query (e.g. ['major-trails-layer']) + * @param {object} options - { returnAll: true } to return array of all matching features + * @returns {object|object[]|null} First matching feature, or array if returnAll, or null + */ +export const getFeaturesAtPoint = (map, event, layerIds, options = {}) => { + if (!map || !event?.lngLat) return options.returnAll ? [] : null; + + const matchLayer = (f) => f.layer?.id && layerIds.includes(f.layer.id); + + // 1. Try event.features + if (event.features?.length) { + const found = event.features.filter(matchLayer); + if (found.length) return options.returnAll ? found : found[0]; + } + + // 2. queryRenderedFeatures at center + tolerance points + const { lng, lat } = event.lngLat; + const centerPoint = [lng, lat]; + const layerFilter = { layers: layerIds }; + + try { + let features = map.queryRenderedFeatures(centerPoint, layerFilter).filter(matchLayer); + if (features.length) return options.returnAll ? features : features[0]; + + // 3. Try points around click (for thin lines) + const zoom = map.getZoom(); + const t = Math.max(0.0001, 0.0005 / Math.pow(2, zoom - 10)); + const points = [ + centerPoint, + [lng + t, lat], [lng - t, lat], [lng, lat + t], [lng, lat - t], + [lng + t, lat + t], [lng - t, lat - t], [lng + t, lat - t], [lng - t, lat + t] + ]; + + for (const pt of points) { + features = map.queryRenderedFeatures(pt, layerFilter).filter(matchLayer); + if (features.length) return options.returnAll ? features : features[0]; + } + + // 4. Fallback: query all layers at point + const all = map.queryRenderedFeatures(centerPoint).filter(matchLayer); + if (all.length) return options.returnAll ? all : all[0]; + } catch (err) { + console.warn("Error querying features at point:", err.message); + } + + return options.returnAll ? [] : null; +}; diff --git a/src/components/Map/utils/municipalityUtils.js b/src/components/Map/utils/municipalityUtils.js new file mode 100644 index 0000000..6f46aff --- /dev/null +++ b/src/components/Map/utils/municipalityUtils.js @@ -0,0 +1,17 @@ +import muniKeys from "../../../data/ma_muni_keys.json"; + +/** + * Get municipality name from muni_id + * @param {string|number} muniId - Municipality ID + * @returns {string|null} Municipality name or null if not found/invalid + */ +export const getMunicipalityName = (muniId) => { + if (!muniId || muniId === "Null" || muniId === "" || muniId === 0) return null; + const municipality = muniKeys.find( + (muni) => + muni.muni_id === parseInt(muniId) || + muni.muni_id === muniId || + muni.muni_id.toString() === muniId.toString() + ); + return municipality ? municipality.muni_name : null; +}; diff --git a/src/components/Map/utils/trailQueries.js b/src/components/Map/utils/trailQueries.js index 27ce4eb..27256f9 100644 --- a/src/components/Map/utils/trailQueries.js +++ b/src/components/Map/utils/trailQueries.js @@ -1,5 +1,4 @@ -import { FEATURE_SERVER_BASE } from "../constants/mapConstants"; -import { geojsonTrailLayers } from "../constants/geojsonTrailLayers"; +import { trailsProfileLayers } from "../constants/mapConstants"; /** * Convert GeoJSON Polygon/MultiPolygon to ESRI Polygon JSON @@ -72,7 +71,7 @@ export const fetchAllFeaturesForLayer = async ({ layerId, esriPolygon }) => { params.set("resultRecordCount", String(pageSize)); // Use POST to avoid "request too long" for large polygons (e.g., Boston) - const url = `${FEATURE_SERVER_BASE}/${layerId}/query`; + const url = `${process.env.REACT_APP_FEATURE_SERVER_BASE}/${layerId}/query`; const res = await fetch(url, { method: "POST", headers: { @@ -127,7 +126,7 @@ export const queryMunicipalityTrails = async ({ try { const allTrailResults = []; - const totalLayers = geojsonTrailLayers.length; + const totalLayers = trailsProfileLayers.length; const isCommunityTrailsProfile = location?.pathname === "/communityTrailsProfile"; const esriPolygon = geojsonPolygonToEsriPolygon(municipality.geometry); @@ -138,8 +137,8 @@ export const queryMunicipalityTrails = async ({ return; } - for (let i = 0; i < geojsonTrailLayers.length; i++) { - const layer = geojsonTrailLayers[i]; + for (let i = 0; i < trailsProfileLayers.length; i++) { + const layer = trailsProfileLayers[i]; setLoadingMessage(`Querying ${layer.name}...`); setLoadingProgress((i / totalLayers) * 80); diff --git a/src/styles/App.scss b/src/styles/App.scss index 5abf86d..a3c608e 100644 --- a/src/styles/App.scss +++ b/src/styles/App.scss @@ -17,4 +17,4 @@ @import "./LoadingBar.scss"; @import "./TrailListWindow.scss"; @import "./BufferAnalysisWindow.scss"; -@import "../components/Map/ProjectMetricsPanel.scss"; \ No newline at end of file +@import "./ProjectMetricsPanel.scss"; \ No newline at end of file diff --git a/src/styles/ControlPanel.scss b/src/styles/ControlPanel.scss index 863eddd..5739322 100644 --- a/src/styles/ControlPanel.scss +++ b/src/styles/ControlPanel.scss @@ -1,4 +1,13 @@ .ControlPanel { + background-color: $lighter-blue; + box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 10px 2px; + font-size: $body-font-size; + height: 100vh; + left: 0; + top: 60px; + width: 260px; + z-index: 6; + &__toggle-btn { transition: all 0.3s ease; font-weight: 500; @@ -8,20 +17,11 @@ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); } } - background-color: $lighter-blue; - box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 10px 2px; - font-size: $body-font-size; - height: 100vh; - left: 0; - top: 60px; - z-index: 6; @media only screen and (max-height: 920px) and (min-width: 1000px) { width: 275px; } - width: 260px; - &_opacity { background-color: $lighter-blue; height: 3rem; diff --git a/src/styles/Header.scss b/src/styles/Header.scss index 291f67f..3b0e67c 100644 --- a/src/styles/Header.scss +++ b/src/styles/Header.scss @@ -10,6 +10,9 @@ } &__title { + color: $white; + margin: unset; + @media only screen and (max-width: 790px) { font-size: 1.25rem; } @@ -41,9 +44,6 @@ padding: 0 20px 0 0; } } - - color: $white; - margin: unset; } &__about { diff --git a/src/styles/Map.scss b/src/styles/Map.scss index f402d6a..2133d75 100644 --- a/src/styles/Map.scss +++ b/src/styles/Map.scss @@ -67,8 +67,8 @@ } } -// Project Trails Profile Map - prevent scrolling -.project-trails-profile-map { +// Regional Trails Profile Map - prevent scrolling +.regional-trails-profile-map { height: 100%; width: 100%; overflow: hidden; @@ -84,7 +84,7 @@ width: 240px; } -// Geocoder styling to fit control panel width for project trails profile +// Geocoder styling to fit control panel width for regional trails profile .mapboxgl-ctrl-geocoder { width: 100% !important; max-width: 520px; @@ -106,8 +106,8 @@ } } -// Geocoder for project trails profile - same positioning as community profile -.project-trails-profile-map .mapboxgl-ctrl-top-left .mapboxgl-ctrl.mapboxgl-ctrl-geocoder { +// Geocoder for regional trails profile - same positioning as community profile +.regional-trails-profile-map .mapboxgl-ctrl-top-left .mapboxgl-ctrl.mapboxgl-ctrl-geocoder { width: 240px !important; @media only screen and (max-height: 920px) and (min-width: 1000px) { diff --git a/src/styles/Popup.scss b/src/styles/Popup.scss index 63b5d71..0e35e4c 100644 --- a/src/styles/Popup.scss +++ b/src/styles/Popup.scss @@ -59,3 +59,6 @@ background-size: 60% 60%; } } + + + diff --git a/src/components/Map/ProjectMetricsPanel.scss b/src/styles/ProjectMetricsPanel.scss similarity index 61% rename from src/components/Map/ProjectMetricsPanel.scss rename to src/styles/ProjectMetricsPanel.scss index 34f1789..d788212 100644 --- a/src/components/Map/ProjectMetricsPanel.scss +++ b/src/styles/ProjectMetricsPanel.scss @@ -2,24 +2,27 @@ position: absolute; left: 280px; // Position after the control panel top: 60px; // Below header - width: 350px; + width: 380px; height: calc(100vh - 60px); background-color: $lighter-blue; - box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 10px 2px; + box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 12px 2px; z-index: 5; // Below control panel display: flex; flex-direction: column; + border-radius: 0 8px 8px 0; &__header { - padding: 20px; + padding: 18px 20px; border-bottom: 2px solid #dee2e6; - background-color: rgba(255, 255, 255, 0.5); + background-color: #ffffff; + flex-shrink: 0; h5 { font-family: $title-font; - font-size: 16px; + font-size: 17px; font-weight: 600; color: #2774bd; + margin: 0; } } @@ -27,20 +30,22 @@ flex: 1; overflow-y: auto; overflow-x: hidden; - padding: 20px; + padding: 16px; + background-color: #f5f7fa; // Custom scrollbar styling &::-webkit-scrollbar { - width: 8px; + width: 10px; } &::-webkit-scrollbar-track { background: rgba(0, 0, 0, 0.05); + border-radius: 5px; } &::-webkit-scrollbar-thumb { background: rgba(39, 116, 189, 0.3); - border-radius: 4px; + border-radius: 5px; &:hover { background: rgba(39, 116, 189, 0.5); @@ -48,9 +53,21 @@ } } + // Regional trails metrics card styles + .project-metrics-card { + &:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + } + } + // Responsive width for larger screens @media only screen and (min-width: 1200px) { - width: 400px; + width: 420px; + } + + @media only screen and (max-width: 1024px) { + width: 320px; + left: 260px; } } diff --git a/webpack.config.js b/webpack.config.js index 5b472a0..c8fed78 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -20,12 +20,6 @@ module.exports = { exclude: /node_modules/, use: ['babel-loader'] }, - { - test: /\.(js|css)$/, - enforce: 'pre', - use: ['source-map-loader'], - exclude: /node_modules\/style-loader/, - }, { test: /\.svg$/, use: [ @@ -42,7 +36,14 @@ module.exports = { use: [ "style-loader", "css-loader", - "sass-loader", + { + loader: "sass-loader", + options: { + sassOptions: { + quietDeps: true, + }, + }, + }, ], }, { diff --git a/yarn.lock b/yarn.lock index eab43fb..1c9c5e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,6 +10,13 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" +"@babel/code-frame@7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== + dependencies: + "@babel/highlight" "^7.8.3" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.24.7", "@babel/code-frame@^7.8.3": version "7.24.7" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz" @@ -18,39 +25,11 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" -"@babel/code-frame@7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== - dependencies: - "@babel/highlight" "^7.8.3" - "@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.2", "@babel/compat-data@^7.25.4", "@babel/compat-data@^7.9.0": version "7.25.4" resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz" integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ== -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.0.0-0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.1.0", "@babel/core@^7.12.0", "@babel/core@^7.13.0", "@babel/core@^7.18.6", "@babel/core@^7.4.0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.4.5": - version "7.25.2" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz" - integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.25.0" - "@babel/helper-compilation-targets" "^7.25.2" - "@babel/helper-module-transforms" "^7.25.2" - "@babel/helpers" "^7.25.0" - "@babel/parser" "^7.25.0" - "@babel/template" "^7.25.0" - "@babel/traverse" "^7.25.2" - "@babel/types" "^7.25.2" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - "@babel/core@7.9.0": version "7.9.0" resolved "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz" @@ -73,6 +52,27 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/core@^7.1.0", "@babel/core@^7.18.6", "@babel/core@^7.4.5": + version "7.25.2" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz" + integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-module-transforms" "^7.25.2" + "@babel/helpers" "^7.25.0" + "@babel/parser" "^7.25.0" + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.2" + "@babel/types" "^7.25.2" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + "@babel/generator@^7.25.0", "@babel/generator@^7.25.4", "@babel/generator@^7.4.0", "@babel/generator@^7.9.0": version "7.25.5" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.25.5.tgz" @@ -352,7 +352,7 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3", "@babel/plugin-proposal-nullish-coalescing-operator@7.8.3": +"@babel/plugin-proposal-nullish-coalescing-operator@7.8.3", "@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": version "7.8.3" resolved "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz" integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== @@ -360,7 +360,7 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" -"@babel/plugin-proposal-numeric-separator@^7.8.3", "@babel/plugin-proposal-numeric-separator@7.8.3": +"@babel/plugin-proposal-numeric-separator@7.8.3", "@babel/plugin-proposal-numeric-separator@^7.8.3": version "7.8.3" resolved "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz" integrity sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ== @@ -387,7 +387,7 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@^7.9.0", "@babel/plugin-proposal-optional-chaining@7.9.0": +"@babel/plugin-proposal-optional-chaining@7.9.0", "@babel/plugin-proposal-optional-chaining@^7.9.0": version "7.9.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz" integrity sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w== @@ -889,6 +889,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.8" +"@babel/plugin-transform-react-display-name@7.8.3", "@babel/plugin-transform-react-display-name@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz" + integrity sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-transform-react-display-name@^7.24.7": version "7.24.7" resolved "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz" @@ -896,13 +903,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-react-display-name@^7.8.3", "@babel/plugin-transform-react-display-name@7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz" - integrity sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-react-jsx-development@^7.24.7", "@babel/plugin-transform-react-jsx-development@^7.9.0": version "7.24.7" resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz" @@ -1046,6 +1046,72 @@ "@babel/helper-create-regexp-features-plugin" "^7.25.2" "@babel/helper-plugin-utils" "^7.24.8" +"@babel/preset-env@7.9.0": + version "7.9.0" + resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.0.tgz" + integrity sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ== + dependencies: + "@babel/compat-data" "^7.9.0" + "@babel/helper-compilation-targets" "^7.8.7" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-proposal-async-generator-functions" "^7.8.3" + "@babel/plugin-proposal-dynamic-import" "^7.8.3" + "@babel/plugin-proposal-json-strings" "^7.8.3" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-proposal-numeric-separator" "^7.8.3" + "@babel/plugin-proposal-object-rest-spread" "^7.9.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining" "^7.9.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.8.0" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-transform-arrow-functions" "^7.8.3" + "@babel/plugin-transform-async-to-generator" "^7.8.3" + "@babel/plugin-transform-block-scoped-functions" "^7.8.3" + "@babel/plugin-transform-block-scoping" "^7.8.3" + "@babel/plugin-transform-classes" "^7.9.0" + "@babel/plugin-transform-computed-properties" "^7.8.3" + "@babel/plugin-transform-destructuring" "^7.8.3" + "@babel/plugin-transform-dotall-regex" "^7.8.3" + "@babel/plugin-transform-duplicate-keys" "^7.8.3" + "@babel/plugin-transform-exponentiation-operator" "^7.8.3" + "@babel/plugin-transform-for-of" "^7.9.0" + "@babel/plugin-transform-function-name" "^7.8.3" + "@babel/plugin-transform-literals" "^7.8.3" + "@babel/plugin-transform-member-expression-literals" "^7.8.3" + "@babel/plugin-transform-modules-amd" "^7.9.0" + "@babel/plugin-transform-modules-commonjs" "^7.9.0" + "@babel/plugin-transform-modules-systemjs" "^7.9.0" + "@babel/plugin-transform-modules-umd" "^7.9.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" + "@babel/plugin-transform-new-target" "^7.8.3" + "@babel/plugin-transform-object-super" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.8.7" + "@babel/plugin-transform-property-literals" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.7" + "@babel/plugin-transform-reserved-words" "^7.8.3" + "@babel/plugin-transform-shorthand-properties" "^7.8.3" + "@babel/plugin-transform-spread" "^7.8.3" + "@babel/plugin-transform-sticky-regex" "^7.8.3" + "@babel/plugin-transform-template-literals" "^7.8.3" + "@babel/plugin-transform-typeof-symbol" "^7.8.4" + "@babel/plugin-transform-unicode-regex" "^7.8.3" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.9.0" + browserslist "^4.9.1" + core-js-compat "^3.6.2" + invariant "^2.2.2" + levenary "^1.1.1" + semver "^5.5.0" + "@babel/preset-env@^7.18.6", "@babel/preset-env@^7.4.5": version "7.25.4" resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz" @@ -1135,71 +1201,14 @@ core-js-compat "^3.37.1" semver "^6.3.1" -"@babel/preset-env@7.9.0": - version "7.9.0" - resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.0.tgz" - integrity sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ== +"@babel/preset-modules@0.1.6-no-external-plugins": + version "0.1.6-no-external-plugins" + resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz" + integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== dependencies: - "@babel/compat-data" "^7.9.0" - "@babel/helper-compilation-targets" "^7.8.7" - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-proposal-async-generator-functions" "^7.8.3" - "@babel/plugin-proposal-dynamic-import" "^7.8.3" - "@babel/plugin-proposal-json-strings" "^7.8.3" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-proposal-numeric-separator" "^7.8.3" - "@babel/plugin-proposal-object-rest-spread" "^7.9.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" - "@babel/plugin-proposal-optional-chaining" "^7.9.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" - "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-json-strings" "^7.8.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.8.0" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - "@babel/plugin-transform-arrow-functions" "^7.8.3" - "@babel/plugin-transform-async-to-generator" "^7.8.3" - "@babel/plugin-transform-block-scoped-functions" "^7.8.3" - "@babel/plugin-transform-block-scoping" "^7.8.3" - "@babel/plugin-transform-classes" "^7.9.0" - "@babel/plugin-transform-computed-properties" "^7.8.3" - "@babel/plugin-transform-destructuring" "^7.8.3" - "@babel/plugin-transform-dotall-regex" "^7.8.3" - "@babel/plugin-transform-duplicate-keys" "^7.8.3" - "@babel/plugin-transform-exponentiation-operator" "^7.8.3" - "@babel/plugin-transform-for-of" "^7.9.0" - "@babel/plugin-transform-function-name" "^7.8.3" - "@babel/plugin-transform-literals" "^7.8.3" - "@babel/plugin-transform-member-expression-literals" "^7.8.3" - "@babel/plugin-transform-modules-amd" "^7.9.0" - "@babel/plugin-transform-modules-commonjs" "^7.9.0" - "@babel/plugin-transform-modules-systemjs" "^7.9.0" - "@babel/plugin-transform-modules-umd" "^7.9.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" - "@babel/plugin-transform-new-target" "^7.8.3" - "@babel/plugin-transform-object-super" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.8.7" - "@babel/plugin-transform-property-literals" "^7.8.3" - "@babel/plugin-transform-regenerator" "^7.8.7" - "@babel/plugin-transform-reserved-words" "^7.8.3" - "@babel/plugin-transform-shorthand-properties" "^7.8.3" - "@babel/plugin-transform-spread" "^7.8.3" - "@babel/plugin-transform-sticky-regex" "^7.8.3" - "@babel/plugin-transform-template-literals" "^7.8.3" - "@babel/plugin-transform-typeof-symbol" "^7.8.4" - "@babel/plugin-transform-unicode-regex" "^7.8.3" - "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.9.0" - browserslist "^4.9.1" - core-js-compat "^3.6.2" - invariant "^2.2.2" - levenary "^1.1.1" - semver "^5.5.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/types" "^7.4.4" + esutils "^2.0.2" "@babel/preset-modules@^0.1.3": version "0.1.6" @@ -1212,14 +1221,17 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-modules@0.1.6-no-external-plugins": - version "0.1.6-no-external-plugins" - resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz" - integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== +"@babel/preset-react@7.9.1": + version "7.9.1" + resolved "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.9.1.tgz" + integrity sha512-aJBYF23MPj0RNdp/4bHnAP0NVqqZRr9kl0NAOP4nJCex6OYVio59+dnQzsAWFuogdLyeaKA1hmfUIVZkY5J+TQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/types" "^7.4.4" - esutils "^2.0.2" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-transform-react-display-name" "^7.8.3" + "@babel/plugin-transform-react-jsx" "^7.9.1" + "@babel/plugin-transform-react-jsx-development" "^7.9.0" + "@babel/plugin-transform-react-jsx-self" "^7.9.0" + "@babel/plugin-transform-react-jsx-source" "^7.9.0" "@babel/preset-react@^7.0.0", "@babel/preset-react@^7.18.6": version "7.24.7" @@ -1233,18 +1245,6 @@ "@babel/plugin-transform-react-jsx-development" "^7.24.7" "@babel/plugin-transform-react-pure-annotations" "^7.24.7" -"@babel/preset-react@7.9.1": - version "7.9.1" - resolved "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.9.1.tgz" - integrity sha512-aJBYF23MPj0RNdp/4bHnAP0NVqqZRr9kl0NAOP4nJCex6OYVio59+dnQzsAWFuogdLyeaKA1hmfUIVZkY5J+TQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-react-display-name" "^7.8.3" - "@babel/plugin-transform-react-jsx" "^7.9.1" - "@babel/plugin-transform-react-jsx-development" "^7.9.0" - "@babel/plugin-transform-react-jsx-self" "^7.9.0" - "@babel/plugin-transform-react-jsx-source" "^7.9.0" - "@babel/preset-typescript@7.9.0": version "7.9.0" resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.9.0.tgz" @@ -1266,13 +1266,6 @@ core-js-pure "^3.30.2" regenerator-runtime "^0.14.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.0", "@babel/runtime@^7.21.0", "@babel/runtime@^7.24.7", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": - version "7.25.4" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.4.tgz" - integrity sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w== - dependencies: - regenerator-runtime "^0.14.0" - "@babel/runtime@7.9.0": version "7.9.0" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.0.tgz" @@ -1280,6 +1273,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.0", "@babel/runtime@^7.21.0", "@babel/runtime@^7.24.7", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": + version "7.25.4" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.4.tgz" + integrity sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.24.7", "@babel/template@^7.25.0", "@babel/template@^7.4.0", "@babel/template@^7.8.6": version "7.25.0" resolved "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz" @@ -1338,7 +1338,7 @@ "@math.gl/web-mercator" "^3.1.3" d3-hexbin "^0.2.1" -"@deck.gl/core@^8.0.0", "@deck.gl/core@8.1.9": +"@deck.gl/core@8.1.9": version "8.1.9" resolved "https://registry.npmjs.org/@deck.gl/core/-/core-8.1.9.tgz" integrity sha512-pytTtM05yrwDjU6Y9wiVDfWuZbAaPYvWtJR+7AF7//S5FqS4pc2yumzxVuvuROPnBNmb+OnVojOzkz5hRlk4yg== @@ -1388,7 +1388,7 @@ d3-dsv "^1.0.8" expression-eval "^2.0.0" -"@deck.gl/layers@^8.0.0", "@deck.gl/layers@8.1.9": +"@deck.gl/layers@8.1.9": version "8.1.9" resolved "https://registry.npmjs.org/@deck.gl/layers/-/layers-8.1.9.tgz" integrity sha512-0geHxt48Fkaj/O/qJ+ppW5KrMqP6h8ZQHGrW8xOe3jDyT6Pkxfuhc1gLCd5ZLUZliJ5N30hqpLNvjW99h2RIOg== @@ -1403,7 +1403,7 @@ resolved "https://registry.npmjs.org/@deck.gl/mapbox/-/mapbox-8.1.9.tgz" integrity sha512-qJMNtUK3aVVeXNbpAkn3posQXkJSxjn9yvV4QB58mvYqVWGksWBMr1byqNoBfpEoR4BvWFuk2jcxAmqqOIgSjQ== -"@deck.gl/mesh-layers@^8.0.0", "@deck.gl/mesh-layers@8.1.9": +"@deck.gl/mesh-layers@8.1.9": version "8.1.9" resolved "https://registry.npmjs.org/@deck.gl/mesh-layers/-/mesh-layers-8.1.9.tgz" integrity sha512-Myxx244Bn0AyW6PQY50LtoW7A+kcydlhApVqFTjcUtmKetuoAhX4CmUk7z2JDQ3T2oj+aZlhJSh0A/CclzTKdw== @@ -1423,6 +1423,23 @@ resolved "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== +"@emotion/is-prop-valid@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz#e9ad47adff0b5c94c72db3669ce46de33edf28c0" + integrity sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw== + dependencies: + "@emotion/memoize" "^0.9.0" + +"@emotion/memoize@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102" + integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== + +"@emotion/unitless@0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745" + integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg== + "@hapi/address@2.x.x": version "2.1.4" resolved "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz" @@ -1433,7 +1450,7 @@ resolved "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz" integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA== -"@hapi/hoek@^8.3.0", "@hapi/hoek@8.x.x": +"@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0": version "8.5.1" resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz" integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== @@ -1663,7 +1680,7 @@ "@math.gl/geospatial" "^3.3.0" "@probe.gl/stats" "^3.3.0" -"@loaders.gl/core@^2.1.6", "@loaders.gl/core@2.3.13": +"@loaders.gl/core@2.3.13", "@loaders.gl/core@^2.1.6": version "2.3.13" resolved "https://registry.npmjs.org/@loaders.gl/core/-/core-2.3.13.tgz" integrity sha512-Hjm8eJjS/OUnaHrOSgXtE+qDg5V4Do0jIpp2u0Dv3CMxPrtd2TpwkDfAyZWmmbZew9rzqPoAVMINejS/ItWUeg== @@ -1680,17 +1697,6 @@ "@loaders.gl/loader-utils" "2.3.13" draco3d "^1.3.6" -"@loaders.gl/draco@3.4.15": - version "3.4.15" - resolved "https://registry.npmjs.org/@loaders.gl/draco/-/draco-3.4.15.tgz" - integrity sha512-SStmyP0ZnS4JbWZb2NhrfiHW65uy3pVTTzQDTgXfkR5cD9oDAEu4nCaHbQ8x38/m39FHliCPgS9b1xWvLKQo8w== - dependencies: - "@babel/runtime" "^7.3.1" - "@loaders.gl/loader-utils" "3.4.15" - "@loaders.gl/schema" "3.4.15" - "@loaders.gl/worker-utils" "3.4.15" - draco3d "1.5.5" - "@loaders.gl/gis@2.3.13": version "2.3.13" resolved "https://registry.npmjs.org/@loaders.gl/gis/-/gis-2.3.13.tgz" @@ -1700,17 +1706,6 @@ "@mapbox/vector-tile" "^1.3.1" pbf "^3.2.1" -"@loaders.gl/gltf@^3.0.0": - version "3.4.15" - resolved "https://registry.npmjs.org/@loaders.gl/gltf/-/gltf-3.4.15.tgz" - integrity sha512-Y6kMNPLiHQPr6aWQw/4BMTxgPHWx3fcib4LPpZCbhyfM8PRn6pOqATVngUXdoOf5XY0QtdKVld6N1kxlr4pJtw== - dependencies: - "@loaders.gl/draco" "3.4.15" - "@loaders.gl/images" "3.4.15" - "@loaders.gl/loader-utils" "3.4.15" - "@loaders.gl/textures" "3.4.15" - "@math.gl/core" "^3.5.1" - "@loaders.gl/gltf@2.3.13": version "2.3.13" resolved "https://registry.npmjs.org/@loaders.gl/gltf/-/gltf-2.3.13.tgz" @@ -1721,27 +1716,13 @@ "@loaders.gl/images" "2.3.13" "@loaders.gl/loader-utils" "2.3.13" -"@loaders.gl/images@^2.1.6", "@loaders.gl/images@2.3.13": +"@loaders.gl/images@2.3.13", "@loaders.gl/images@^2.1.6": version "2.3.13" resolved "https://registry.npmjs.org/@loaders.gl/images/-/images-2.3.13.tgz" integrity sha512-BBgLf17udhRnYwvsObAOM7jEeLBaeU3di1NyLhpTMa7WbG3jAnDlmy1BRue8wYfgVpWnmk18YubZtX6vCRrJnA== dependencies: "@loaders.gl/loader-utils" "2.3.13" -"@loaders.gl/images@^3.0.0": - version "3.4.15" - resolved "https://registry.npmjs.org/@loaders.gl/images/-/images-3.4.15.tgz" - integrity sha512-QpjYhEetHabY/z9mWZYJXZZp4XJAxa38f9Ii/DjPlnJErepzY5GLBUTDHMu4oZ6n99gGImtuGFicDnFV6mb60g== - dependencies: - "@loaders.gl/loader-utils" "3.4.15" - -"@loaders.gl/images@3.4.15": - version "3.4.15" - resolved "https://registry.npmjs.org/@loaders.gl/images/-/images-3.4.15.tgz" - integrity sha512-QpjYhEetHabY/z9mWZYJXZZp4XJAxa38f9Ii/DjPlnJErepzY5GLBUTDHMu4oZ6n99gGImtuGFicDnFV6mb60g== - dependencies: - "@loaders.gl/loader-utils" "3.4.15" - "@loaders.gl/loader-utils@2.3.13": version "2.3.13" resolved "https://registry.npmjs.org/@loaders.gl/loader-utils/-/loader-utils-2.3.13.tgz" @@ -1750,15 +1731,6 @@ "@babel/runtime" "^7.3.1" "@probe.gl/stats" "^3.3.0" -"@loaders.gl/loader-utils@3.4.15": - version "3.4.15" - resolved "https://registry.npmjs.org/@loaders.gl/loader-utils/-/loader-utils-3.4.15.tgz" - integrity sha512-uUx6tCaky6QgCRkqCNuuXiUfpTzKV+ZlJOf6C9bKp62lpvFOv9AwqoXmL23j8nfsENdlzsX3vPhc3en6QQyksA== - dependencies: - "@babel/runtime" "^7.3.1" - "@loaders.gl/worker-utils" "3.4.15" - "@probe.gl/stats" "^3.5.0" - "@loaders.gl/math@2.3.13": version "2.3.13" resolved "https://registry.npmjs.org/@loaders.gl/math/-/math-2.3.13.tgz" @@ -1779,13 +1751,6 @@ "@mapbox/vector-tile" "^1.3.1" pbf "^3.2.1" -"@loaders.gl/schema@3.4.15": - version "3.4.15" - resolved "https://registry.npmjs.org/@loaders.gl/schema/-/schema-3.4.15.tgz" - integrity sha512-8oRtstz0IsqES7eZd2jQbmCnmExCMtL8T6jWd1+BfmnuyZnQ0B6TNccy++NHtffHdYuzEoQgSELwcdmhSApYew== - dependencies: - "@types/geojson" "^7946.0.7" - "@loaders.gl/terrain@^2.1.6": version "2.3.13" resolved "https://registry.npmjs.org/@loaders.gl/terrain/-/terrain-2.3.13.tgz" @@ -1795,19 +1760,7 @@ "@loaders.gl/loader-utils" "2.3.13" "@mapbox/martini" "^0.2.0" -"@loaders.gl/textures@3.4.15": - version "3.4.15" - resolved "https://registry.npmjs.org/@loaders.gl/textures/-/textures-3.4.15.tgz" - integrity sha512-QHnmxBYtLvTdG1uMz2KWcxVY8KPb1+XyPJUoZV9GMcQkulz+CwFB8BaX8nROfMDz9KKYoPfksCzjig0LZ0WBJQ== - dependencies: - "@loaders.gl/images" "3.4.15" - "@loaders.gl/loader-utils" "3.4.15" - "@loaders.gl/schema" "3.4.15" - "@loaders.gl/worker-utils" "3.4.15" - ktx-parse "^0.0.4" - texture-compressor "^1.0.2" - -"@loaders.gl/tiles@^2.1.6", "@loaders.gl/tiles@2.3.13": +"@loaders.gl/tiles@2.3.13", "@loaders.gl/tiles@^2.1.6": version "2.3.13" resolved "https://registry.npmjs.org/@loaders.gl/tiles/-/tiles-2.3.13.tgz" integrity sha512-3ZSlMgcPTo5lCnvKw/is5dvTayzvX+wi6n1u4lEe4gt8Ml9KYp/e45hOqp6qXR6SckO2+ohBXOzQP2e8ZhRxXQ== @@ -1821,13 +1774,6 @@ "@math.gl/web-mercator" "^3.3.0" "@probe.gl/stats" "^3.3.0" -"@loaders.gl/worker-utils@3.4.15": - version "3.4.15" - resolved "https://registry.npmjs.org/@loaders.gl/worker-utils/-/worker-utils-3.4.15.tgz" - integrity sha512-zUUepOYRYmcYIcr/c4Mchox9h5fBFNkD81rsGnLlZyq19QvyHzN+93SVxrLc078gw93t2RKrVcOOZY13zT3t1w== - dependencies: - "@babel/runtime" "^7.3.1" - "@luma.gl/constants@8.5.21": version "8.5.21" resolved "https://registry.npmjs.org/@luma.gl/constants/-/constants-8.5.21.tgz" @@ -1845,7 +1791,7 @@ "@luma.gl/shadertools" "8.5.21" "@luma.gl/webgl" "8.5.21" -"@luma.gl/engine@^8.4.0", "@luma.gl/engine@8.5.21": +"@luma.gl/engine@8.5.21": version "8.5.21" resolved "https://registry.npmjs.org/@luma.gl/engine/-/engine-8.5.21.tgz" integrity sha512-IG3WQSKXFNUEs8QG7ZjHtGiOtsakUu+BAxtJ6997A6/F06yynZ44tPe5NU70jG9Yfu3kV0LykPZg7hO3vXZDiA== @@ -1869,7 +1815,7 @@ "@math.gl/core" "^3.5.0" earcut "^2.0.6" -"@luma.gl/gltools@^8.4.0", "@luma.gl/gltools@8.5.21": +"@luma.gl/gltools@8.5.21": version "8.5.21" resolved "https://registry.npmjs.org/@luma.gl/gltools/-/gltools-8.5.21.tgz" integrity sha512-6qZ0LaT2Mxa4AJT5F44TFoaziokYiHUwO45vnM/NYUOIu9xevcmS6VtToawytMEACGL6PDeDyVqP3Y80SDzq5g== @@ -1880,7 +1826,7 @@ "@probe.gl/log" "^3.5.0" "@types/offscreencanvas" "^2019.7.0" -"@luma.gl/shadertools@^8.1.2", "@luma.gl/shadertools@^8.4.0", "@luma.gl/shadertools@8.5.21": +"@luma.gl/shadertools@8.5.21", "@luma.gl/shadertools@^8.1.2": version "8.5.21" resolved "https://registry.npmjs.org/@luma.gl/shadertools/-/shadertools-8.5.21.tgz" integrity sha512-WQah7yFDJ8cNCLPYpIm3r0wSlXLvjoA279fcknmATvvkW3/i8PcCJ/nYEBJO3hHEwwMQxD16+YZu/uwGiifLMg== @@ -1888,7 +1834,7 @@ "@babel/runtime" "^7.0.0" "@math.gl/core" "^3.5.0" -"@luma.gl/webgl@^8.4.0", "@luma.gl/webgl@8.5.21": +"@luma.gl/webgl@8.5.21": version "8.5.21" resolved "https://registry.npmjs.org/@luma.gl/webgl/-/webgl-8.5.21.tgz" integrity sha512-ZVLO4W5UuaOlzZIwmFWhnmZ1gYoU97a+heMqxLrSSmCUAsSu3ZETUex9gOmzdM1WWxcdWaa3M68rvKCNEgwz0Q== @@ -1915,29 +1861,11 @@ get-stream "^6.0.1" minimist "^1.2.6" -"@mapbox/geojson-types@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz" - integrity sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw== - "@mapbox/jsonlint-lines-primitives@^2.0.2", "@mapbox/jsonlint-lines-primitives@~2.0.2": version "2.0.2" resolved "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz" integrity sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ== -"@mapbox/mapbox-gl-geocoder@^5.0.1": - version "5.0.2" - resolved "https://registry.npmjs.org/@mapbox/mapbox-gl-geocoder/-/mapbox-gl-geocoder-5.0.2.tgz" - integrity sha512-o+2atyKKsfbiI2/iutQ/razt5O++kfi9oxwaXSfKc6m/9NudJnQm3rpGB0GagA+becq2NU4U99E9Yzv+UcMCBQ== - dependencies: - "@mapbox/mapbox-sdk" "^0.13.7" - events "^3.3.0" - lodash.debounce "^4.0.6" - nanoid "^3.1.31" - subtag "^0.5.0" - suggestions "^1.6.0" - xtend "^4.0.1" - "@mapbox/mapbox-gl-geocoder@4.7.0": version "4.7.0" resolved "https://registry.npmjs.org/@mapbox/mapbox-gl-geocoder/-/mapbox-gl-geocoder-4.7.0.tgz" @@ -1950,10 +1878,18 @@ suggestions "^1.6.0" xtend "^4.0.1" -"@mapbox/mapbox-gl-supported@^1.5.0": - version "1.5.0" - resolved "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.5.0.tgz" - integrity sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg== +"@mapbox/mapbox-gl-geocoder@^5.0.1": + version "5.0.2" + resolved "https://registry.npmjs.org/@mapbox/mapbox-gl-geocoder/-/mapbox-gl-geocoder-5.0.2.tgz" + integrity sha512-o+2atyKKsfbiI2/iutQ/razt5O++kfi9oxwaXSfKc6m/9NudJnQm3rpGB0GagA+becq2NU4U99E9Yzv+UcMCBQ== + dependencies: + "@mapbox/mapbox-sdk" "^0.13.7" + events "^3.3.0" + lodash.debounce "^4.0.6" + nanoid "^3.1.31" + subtag "^0.5.0" + suggestions "^1.6.0" + xtend "^4.0.1" "@mapbox/mapbox-gl-supported@^2.0.1": version "2.0.1" @@ -2000,7 +1936,7 @@ dependencies: base-64 "^0.1.0" -"@mapbox/point-geometry@^0.1.0", "@mapbox/point-geometry@~0.1.0", "@mapbox/point-geometry@0.1.0": +"@mapbox/point-geometry@0.1.0", "@mapbox/point-geometry@^0.1.0", "@mapbox/point-geometry@~0.1.0": version "0.1.0" resolved "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz" integrity sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ== @@ -2021,7 +1957,7 @@ file-saver "2.0.5" jszip "^3.10.1" -"@mapbox/tiny-sdf@^1.1.0", "@mapbox/tiny-sdf@^1.1.1": +"@mapbox/tiny-sdf@^1.1.0": version "1.2.5" resolved "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-1.2.5.tgz" integrity sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw== @@ -2031,11 +1967,6 @@ resolved "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz" integrity sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA== -"@mapbox/unitbezier@^0.0.0": - version "0.0.0" - resolved "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz" - integrity sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA== - "@mapbox/unitbezier@^0.0.1": version "0.0.1" resolved "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz" @@ -2065,7 +1996,7 @@ rw "^1.3.3" sort-object "^3.0.3" -"@math.gl/core@^3.1.3", "@math.gl/core@^3.3.0", "@math.gl/core@^3.5.0", "@math.gl/core@^3.5.1", "@math.gl/core@3.6.3": +"@math.gl/core@3.6.3", "@math.gl/core@^3.1.3", "@math.gl/core@^3.3.0", "@math.gl/core@^3.5.0": version "3.6.3" resolved "https://registry.npmjs.org/@math.gl/core/-/core-3.6.3.tgz" integrity sha512-jBABmDkj5uuuE0dTDmwwss7Cup5ZwQ6Qb7h1pgvtkEutTrhkcv8SuItQNXmF45494yIHeoGue08NlyeY6wxq2A== @@ -2118,19 +2049,19 @@ resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz" integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== -"@popperjs/core@^2.11.6", "@popperjs/core@^2.11.8": +"@popperjs/core@^2.11.6": version "2.11.8" resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== -"@probe.gl/env@^3.5.0", "@probe.gl/env@3.6.0": +"@probe.gl/env@3.6.0", "@probe.gl/env@^3.5.0": version "3.6.0" resolved "https://registry.npmjs.org/@probe.gl/env/-/env-3.6.0.tgz" integrity sha512-4tTZYUg/8BICC3Yyb9rOeoKeijKbZHRXBEKObrfPmX4sQmYB15ZOUpoVBhAyJkOYVAM8EkPci6Uw5dLCwx2BEQ== dependencies: "@babel/runtime" "^7.0.0" -"@probe.gl/log@^3.5.0", "@probe.gl/log@3.6.0": +"@probe.gl/log@3.6.0", "@probe.gl/log@^3.5.0": version "3.6.0" resolved "https://registry.npmjs.org/@probe.gl/log/-/log-3.6.0.tgz" integrity sha512-hjpyenpEvOdowgZ1qMeCJxfRD4JkKdlXz0RC14m42Un62NtOT+GpWyKA4LssT0+xyLULCByRAtG2fzZorpIAcA== @@ -2138,7 +2069,7 @@ "@babel/runtime" "^7.0.0" "@probe.gl/env" "3.6.0" -"@probe.gl/stats@^3.3.0", "@probe.gl/stats@^3.5.0", "@probe.gl/stats@3.6.0": +"@probe.gl/stats@3.6.0", "@probe.gl/stats@^3.3.0", "@probe.gl/stats@^3.5.0": version "3.6.0" resolved "https://registry.npmjs.org/@probe.gl/stats/-/stats-3.6.0.tgz" integrity sha512-JdALQXB44OP4kUBN/UrQgzbJe4qokbVF4Y8lkIA8iVCFnjVowWIgkD/z/0QO65yELT54tTrtepw1jScjKB+rhQ== @@ -3869,7 +3800,7 @@ "@types/qs" "*" "@types/serve-static" "*" -"@types/geojson@*", "@types/geojson@^7946.0.10", "@types/geojson@^7946.0.14", "@types/geojson@^7946.0.7": +"@types/geojson@*", "@types/geojson@^7946.0.10", "@types/geojson@^7946.0.14": version "7946.0.14" resolved "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz" integrity sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg== @@ -4019,7 +3950,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@>=16.14.8", "@types/react@>=16.9.11": +"@types/react@*", "@types/react@>=16.9.11": version "18.3.4" resolved "https://registry.npmjs.org/@types/react/-/react-18.3.4.tgz" integrity sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw== @@ -4075,6 +4006,11 @@ resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/stylis@4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@types/stylis/-/stylis-4.2.7.tgz#1813190525da9d2a2b6976583bdd4af5301d9fd4" + integrity sha512-VgDNokpBoKF+wrdvhAAfS55OMQpL6QRglwTwNC3kIgBrzZxA4WsFj+2eLfEA/uMUDzBcEhYmjSbwQakn/i3ajA== + "@types/warning@^3.0.0": version "3.0.3" resolved "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz" @@ -4099,7 +4035,7 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^2.10.0", "@typescript-eslint/eslint-plugin@2.x": +"@typescript-eslint/eslint-plugin@^2.10.0": version "2.34.0" resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz" integrity sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ== @@ -4119,7 +4055,7 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@^2.0.0", "@typescript-eslint/parser@^2.10.0", "@typescript-eslint/parser@2.x": +"@typescript-eslint/parser@^2.10.0": version "2.34.0" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz" integrity sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA== @@ -4142,7 +4078,7 @@ semver "^7.3.2" tsutils "^3.17.1" -"@webassemblyjs/ast@^1.12.1", "@webassemblyjs/ast@1.12.1": +"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": version "1.12.1" resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz" integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== @@ -4286,20 +4222,6 @@ resolved "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz" integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== -"@webassemblyjs/wasm-edit@^1.12.1": - version "1.12.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz" - integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/helper-wasm-section" "1.12.1" - "@webassemblyjs/wasm-gen" "1.12.1" - "@webassemblyjs/wasm-opt" "1.12.1" - "@webassemblyjs/wasm-parser" "1.12.1" - "@webassemblyjs/wast-printer" "1.12.1" - "@webassemblyjs/wasm-edit@1.8.5": version "1.8.5" resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz" @@ -4314,6 +4236,20 @@ "@webassemblyjs/wasm-parser" "1.8.5" "@webassemblyjs/wast-printer" "1.8.5" +"@webassemblyjs/wasm-edit@^1.12.1": + version "1.12.1" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz" + integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-opt" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + "@webassemblyjs/wast-printer" "1.12.1" + "@webassemblyjs/wasm-gen@1.12.1": version "1.12.1" resolved "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz" @@ -4356,7 +4292,7 @@ "@webassemblyjs/wasm-gen" "1.8.5" "@webassemblyjs/wasm-parser" "1.8.5" -"@webassemblyjs/wasm-parser@^1.12.1", "@webassemblyjs/wasm-parser@1.12.1": +"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": version "1.12.1" resolved "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz" integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== @@ -4477,37 +4413,22 @@ acorn@^5.5.3: resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz" integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -acorn@^6.0.1: +acorn@^6.0.1, acorn@^6.0.4, acorn@^6.2.1: version "6.4.2" resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== -acorn@^6.0.4: - version "6.4.2" - resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== - -acorn@^6.2.1: - version "6.4.2" - resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== - -acorn@^8, acorn@^8.7.1: - version "8.12.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== +acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.8.2: +acorn@^8.7.1, acorn@^8.8.2: version "8.12.1" resolved "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== -address@^1.0.1, address@1.1.2: +address@1.1.2, address@^1.0.1: version "1.1.2" resolved "https://registry.npmjs.org/address/-/address-1.1.2.tgz" integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== @@ -4555,7 +4476,7 @@ ajv-keywords@^5.1.0: dependencies: fast-deep-equal "^3.1.3" -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.9.1, ajv@>=5.0.0: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -4565,17 +4486,7 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5, ajv json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0: - version "8.17.1" - resolved "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz" - integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== - dependencies: - fast-deep-equal "^3.1.3" - fast-uri "^3.0.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - -ajv@^8.8.2, ajv@^8.9.0: +ajv@^8.0.0, ajv@^8.9.0: version "8.17.1" resolved "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz" integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== @@ -4632,12 +4543,7 @@ ansi-regex@^4.0.0, ansi-regex@^4.1.0: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz" integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== -ansi-regex@^5.0.0: - version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-regex@^5.0.1: +ansi-regex@^5.0.0, ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== @@ -4654,7 +4560,7 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -4682,7 +4588,7 @@ aproba@^1.1.1: resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -argparse@^1.0.10, argparse@^1.0.7: +argparse@^1.0.7: version "1.0.10" resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -4730,16 +4636,16 @@ array-equal@^1.0.0: resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.2.tgz" integrity sha512-gUHx76KtnhEgB3HOuFYiCm3FIdEs6ocM2asHvNTkfu/Y09qQVrrVVaOKENmS2KkSaGoxgXNqC+ZVtR/n0MOkSA== -array-flatten@^2.1.0: - version "2.1.2" - resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz" - integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + array-includes@^3.0.3, array-includes@^3.1.1, array-includes@^3.1.6, array-includes@^3.1.8: version "3.1.8" resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz" @@ -4865,12 +4771,12 @@ asn1@~0.2.3: dependencies: safer-buffer "~2.1.0" -assert-plus@^1.0.0, assert-plus@1.0.0: +assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== -assert@^1.1.1, assert@1.4.1: +assert@1.4.1, assert@^1.1.1: version "1.4.1" resolved "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz" integrity sha512-N+aAxov+CKVS3JuhDIQFr24XvZvwE96Wlhk9dytTg/GmwWoghdOvR8dspx8MVz71O+Y0pA3UPqHF68D6iy8UvQ== @@ -4882,7 +4788,7 @@ assign-symbols@^1.0.0: resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz" integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== -ast-types-flow@^0.0.7, ast-types-flow@0.0.7: +ast-types-flow@0.0.7, ast-types-flow@^0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz" integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== @@ -4971,7 +4877,7 @@ babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-eslint@10.1.0, babel-eslint@10.x: +babel-eslint@10.1.0: version "10.1.0" resolved "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz" integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== @@ -5003,16 +4909,6 @@ babel-jest@^24.9.0: chalk "^2.4.2" slash "^2.0.0" -babel-loader@^8.1.0: - version "8.3.0" - resolved "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz" - integrity sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q== - dependencies: - find-cache-dir "^3.3.1" - loader-utils "^2.0.0" - make-dir "^3.1.0" - schema-utils "^2.6.5" - babel-loader@8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz" @@ -5024,6 +4920,16 @@ babel-loader@8.1.0: pify "^4.0.1" schema-utils "^2.6.5" +babel-loader@^8.1.0: + version "8.3.0" + resolved "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz" + integrity sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q== + dependencies: + find-cache-dir "^3.3.1" + loader-utils "^2.0.0" + make-dir "^3.1.0" + schema-utils "^2.6.5" + babel-plugin-istanbul@^5.1.0: version "5.2.0" resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz" @@ -5149,6 +5055,11 @@ base-64@^0.1.0: resolved "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz" integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA== +base64-js@^1.0.2: + version "1.5.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + base@^0.11.1: version "0.11.2" resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz" @@ -5162,11 +5073,6 @@ base@^0.11.1: mixin-deep "^1.2.0" pascalcase "^0.1.1" -base64-js@^1.0.2: - version "1.5.1" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - batch@0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz" @@ -5211,17 +5117,7 @@ bluebird@^3.5.5: resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -bn.js@^4.0.0: - version "4.12.0" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^4.1.0: - version "4.12.0" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^4.11.9: +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== @@ -5303,14 +5199,7 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - -braces@~3.0.2: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -5396,16 +5285,6 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4, browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.21.10, browserslist@^4.23.1, browserslist@^4.23.3, browserslist@^4.6.2, browserslist@^4.6.4, browserslist@^4.9.1, "browserslist@>= 4.21.0": - version "4.23.3" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz" - integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== - dependencies: - caniuse-lite "^1.0.30001646" - electron-to-chromium "^1.5.4" - node-releases "^2.0.18" - update-browserslist-db "^1.1.0" - browserslist@4.10.0: version "4.10.0" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.10.0.tgz" @@ -5416,6 +5295,16 @@ browserslist@4.10.0: node-releases "^1.1.52" pkg-up "^3.1.0" +browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.21.10, browserslist@^4.23.1, browserslist@^4.23.3, browserslist@^4.6.2, browserslist@^4.6.4, browserslist@^4.9.1: + version "4.23.3" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz" + integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== + dependencies: + caniuse-lite "^1.0.30001646" + electron-to-chromium "^1.5.4" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + bser@2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" @@ -5625,16 +5514,21 @@ camelcase-keys@^6.2.2: map-obj "^4.0.0" quick-lru "^4.0.1" -camelcase@^5.0.0, camelcase@^5.3.1, camelcase@5.3.1: - version "5.3.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - camelcase@5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz" integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== +camelcase@5.3.1, camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelize@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3" + integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ== + caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz" @@ -5667,6 +5561,15 @@ caseless@~0.12.0: resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== +chalk@2.4.2, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chalk@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz" @@ -5678,15 +5581,6 @@ chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2, chalk@2.4.2: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - chalk@^4.1.0: version "4.1.2" resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" @@ -5700,6 +5594,21 @@ chardet@^0.7.0: resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.3.0, chokidar@^3.4.1, chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chokidar@^2.1.8: version "2.1.8" resolved "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz" @@ -5719,21 +5628,6 @@ chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" -chokidar@^3.3.0, chokidar@^3.4.1, chokidar@^3.5.3, "chokidar@>=3.0.0 <4.0.0": - version "3.6.0" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" - integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - chownr@^1.1.1, chownr@^1.1.2: version "1.1.4" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" @@ -5826,15 +5720,6 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" - clone-deep@^0.2.4: version "0.2.4" resolved "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz" @@ -5855,13 +5740,6 @@ clone-deep@^4.0.1: kind-of "^6.0.2" shallow-clone "^3.0.0" -clone-response@^1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz" - integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== - dependencies: - mimic-response "^1.0.0" - clone-response@1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz" @@ -5869,6 +5747,13 @@ clone-response@1.0.2: dependencies: mimic-response "^1.0.0" +clone-response@^1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz" + integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== + dependencies: + mimic-response "^1.0.0" + co@^4.6.0: version "4.6.0" resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" @@ -5910,7 +5795,7 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@^1.0.0, color-name@1.1.3: +color-name@1.1.3, color-name@^1.0.0: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== @@ -5948,7 +5833,7 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@^2.11.0, commander@^2.20.0, commander@2: +commander@2, commander@^2.11.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -6035,21 +5920,6 @@ concaveman@^1.2.1: robust-predicates "^2.0.4" tinyqueue "^2.0.3" -concurrently@^7.6.0: - version "7.6.0" - resolved "https://registry.npmjs.org/concurrently/-/concurrently-7.6.0.tgz" - integrity sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw== - dependencies: - chalk "^4.1.0" - date-fns "^2.29.1" - lodash "^4.17.21" - rxjs "^7.0.0" - shell-quote "^1.7.3" - spawn-command "^0.0.2-1" - supports-color "^8.1.0" - tree-kill "^1.2.2" - yargs "^17.3.1" - confusing-browser-globals@^1.0.9: version "1.0.11" resolved "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz" @@ -6092,17 +5962,19 @@ content-type@~1.0.4, content-type@~1.0.5: resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== -convert-source-map@^0.3.3: +convert-source-map@1.7.0: + version "1.7.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +convert-source-map@^0.3.3: version "0.3.5" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz" integrity sha512-+4nRk0k3oEpwUB7/CalD7xE2z4VmtEnnq0GO2IPTkrooTrAhEsWvuLF5iWP1dXrwluki/azwXV1ve7gtYuPldg== -convert-source-map@^1.4.0: - version "1.9.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - -convert-source-map@^1.7.0: +convert-source-map@^1.4.0, convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -6112,13 +5984,6 @@ convert-source-map@^2.0.0: resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -convert-source-map@1.7.0: - version "1.7.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== - dependencies: - safe-buffer "~5.1.1" - cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" @@ -6168,16 +6033,16 @@ core-js@^3.5.0: resolved "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz" integrity sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw== -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - core-util-is@1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + cosmiconfig@^5.0.0, cosmiconfig@^5.2.1: version "5.2.1" resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz" @@ -6230,6 +6095,15 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +cross-spawn@7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz" + integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz" @@ -6250,15 +6124,6 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -cross-spawn@7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz" - integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz" @@ -6283,7 +6148,12 @@ css-blank-pseudo@^0.1.4: dependencies: postcss "^7.0.5" -css-color-names@^0.0.4, css-color-names@0.0.4: +css-color-keywords@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" + integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg== + +css-color-names@0.0.4, css-color-names@^0.0.4: version "0.0.4" resolved "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz" integrity sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q== @@ -6304,20 +6174,6 @@ css-has-pseudo@^0.10.0: postcss "^7.0.6" postcss-selector-parser "^5.0.0-rc.4" -css-loader@^6.7.1: - version "6.11.0" - resolved "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz" - integrity sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g== - dependencies: - icss-utils "^5.1.0" - postcss "^8.4.33" - postcss-modules-extract-imports "^3.1.0" - postcss-modules-local-by-default "^4.0.5" - postcss-modules-scope "^3.2.0" - postcss-modules-values "^4.0.0" - postcss-value-parser "^4.2.0" - semver "^7.5.4" - css-loader@3.4.2: version "3.4.2" resolved "https://registry.npmjs.org/css-loader/-/css-loader-3.4.2.tgz" @@ -6336,6 +6192,20 @@ css-loader@3.4.2: postcss-value-parser "^4.0.2" schema-utils "^2.6.0" +css-loader@^6.7.1: + version "6.11.0" + resolved "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz" + integrity sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g== + dependencies: + icss-utils "^5.1.0" + postcss "^8.4.33" + postcss-modules-extract-imports "^3.1.0" + postcss-modules-local-by-default "^4.0.5" + postcss-modules-scope "^3.2.0" + postcss-modules-values "^4.0.0" + postcss-value-parser "^4.2.0" + semver "^7.5.4" + css-prefers-color-scheme@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz" @@ -6369,13 +6239,14 @@ css-select@^4.1.3: domutils "^2.8.0" nth-check "^2.0.1" -css-tree@^1.1.2: - version "1.1.3" - resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz" - integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== +css-to-react-native@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32" + integrity sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ== dependencies: - mdn-data "2.0.14" - source-map "^0.6.1" + camelize "^1.0.0" + css-color-keywords "^1.0.0" + postcss-value-parser "^4.0.2" css-tree@1.0.0-alpha.37: version "1.0.0-alpha.37" @@ -6385,6 +6256,14 @@ css-tree@1.0.0-alpha.37: mdn-data "2.0.4" source-map "^0.6.1" +css-tree@^1.1.2: + version "1.1.3" + resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + css-what@^3.2.1: version "3.4.2" resolved "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz" @@ -6500,7 +6379,7 @@ csso@^4.0.2: dependencies: css-tree "^1.1.2" -cssom@^0.3.4, "cssom@>= 0.3.2 < 0.4.0", cssom@0.3.x: +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0", cssom@^0.3.4: version "0.3.8" resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== @@ -6512,6 +6391,11 @@ cssstyle@^1.0.0, cssstyle@^1.1.1: dependencies: cssom "0.3.x" +csstype@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a" + integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ== + csstype@^3.0.2: version "3.1.3" resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" @@ -6522,14 +6406,6 @@ cyclist@^1.0.1: resolved "https://registry.npmjs.org/cyclist/-/cyclist-1.0.2.tgz" integrity sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA== -d@^1.0.1, d@^1.0.2, d@1: - version "1.0.2" - resolved "https://registry.npmjs.org/d/-/d-1.0.2.tgz" - integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw== - dependencies: - es5-ext "^0.10.64" - type "^2.7.2" - d3-array@1: version "1.2.4" resolved "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz" @@ -6561,6 +6437,14 @@ d3-voronoi@1.1.2: resolved "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.2.tgz" integrity sha512-RhGS1u2vavcO7ay7ZNAPo4xeDh/VYeGof3x5ZLJBQgYhLegxr3s5IykvWmJ94FTU6mcbtp4sloqZ54mP6R4Utw== +d@1, d@^1.0.1, d@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/d/-/d-1.0.2.tgz" + integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw== + dependencies: + es5-ext "^0.10.64" + type "^2.7.2" + damerau-levenshtein@^1.0.4: version "1.0.8" resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz" @@ -6609,13 +6493,6 @@ data-view-byte-offset@^1.0.0: es-errors "^1.3.0" is-data-view "^1.0.1" -date-fns@^2.29.1: - version "2.30.0" - resolved "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz" - integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== - dependencies: - "@babel/runtime" "^7.21.0" - dbf@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/dbf/-/dbf-0.2.0.tgz" @@ -6623,42 +6500,14 @@ dbf@0.2.0: dependencies: jdataview "~2.5.0" -debug@^2.2.0: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^2.3.3: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^2.6.0: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^2.6.9: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^3.2.5: - version "3.2.7" - resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debug@^3.2.7: +debug@^3.2.5, debug@^3.2.7: version "3.2.7" resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -6672,13 +6521,6 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: dependencies: ms "2.1.2" -debug@2.6.9: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - decamelize-keys@^1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz" @@ -6827,16 +6669,16 @@ delayed-stream@~1.0.0: resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" - integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== - depd@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + dequal@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz" @@ -6922,6 +6764,14 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz" + integrity sha512-lsGyRuYr4/PIB0txi+Fy2xOMI2dGaTguCaotzFGkVZuKR5usKfcRWIFKNM3QNrU7hh/+w2bwTW+ZeXPK5l8uVg== + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + doctrine@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" @@ -6936,14 +6786,6 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz" - integrity sha512-lsGyRuYr4/PIB0txi+Fy2xOMI2dGaTguCaotzFGkVZuKR5usKfcRWIFKNM3QNrU7hh/+w2bwTW+ZeXPK5l8uVg== - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - dom-converter@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz" @@ -6959,6 +6801,14 @@ dom-helpers@^5.0.1, dom-helpers@^5.2.0, dom-helpers@^5.2.1: "@babel/runtime" "^7.8.7" csstype "^3.0.2" +dom-serializer@0: + version "0.2.2" + resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + dom-serializer@^1.0.1: version "1.4.1" resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz" @@ -6968,29 +6818,21 @@ dom-serializer@^1.0.1: domhandler "^4.2.0" entities "^2.0.0" -dom-serializer@0: - version "0.2.2" - resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" - domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== -domelementtype@^2.0.1, domelementtype@^2.2.0: - version "2.3.0" - resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz" - integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== - domelementtype@1: version "1.3.1" resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz" integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + domexception@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz" @@ -7056,41 +6898,31 @@ dotenv-webpack@^8.0.0: dependencies: dotenv-defaults "^2.0.2" -dotenv@^16.0.3: - version "16.6.1" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz" - integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== +dotenv@8.2.0: + version "8.2.0" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz" + integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== dotenv@^8.2.0: version "8.6.0" resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz" integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== -dotenv@8.2.0: - version "8.2.0" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz" - integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== - draco3d@^1.3.6: version "1.5.7" resolved "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz" integrity sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ== -draco3d@1.5.5: - version "1.5.5" - resolved "https://registry.npmjs.org/draco3d/-/draco3d-1.5.5.tgz" - integrity sha512-JVuNV0EJzD3LBYhGyIXJLeBID/EVtmFO1ZNhAYflTgiMiAJlbhXQmRRda/azjc8MRVMHh0gqGhiqHUo5dIXM8Q== +duplexer3@^0.1.4: + version "0.1.5" + resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz" + integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== duplexer@^0.1.1: version "0.1.2" resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== -duplexer3@^0.1.4: - version "0.1.5" - resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz" - integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== - duplexify@^3.4.2, duplexify@^3.6.0: version "3.7.1" resolved "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz" @@ -7101,7 +6933,7 @@ duplexify@^3.4.2, duplexify@^3.6.0: readable-stream "^2.0.0" stream-shift "^1.0.0" -earcut@^2.0.6, earcut@^2.2.2, earcut@^2.2.4: +earcut@^2.0.6, earcut@^2.2.4: version "2.2.4" resolved "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz" integrity sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ== @@ -7346,7 +7178,7 @@ es5-ext@^0.10.35, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14: esniff "^2.0.1" next-tick "^1.1.0" -es6-iterator@^2.0.3, es6-iterator@2.0.3: +es6-iterator@2.0.3, es6-iterator@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz" integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== @@ -7363,7 +7195,7 @@ es6-symbol@^3.1.1, es6-symbol@^3.1.3: d "^1.0.2" ext "^1.7.0" -escalade@^3.1.1, escalade@^3.1.2: +escalade@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== @@ -7373,20 +7205,15 @@ escape-html@~1.0.3: resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^2.0.0: +escape-string-regexp@2.0.0, escape-string-regexp@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escape-string-regexp@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escodegen@^1.11.0, escodegen@^1.9.1: version "1.14.3" @@ -7434,14 +7261,14 @@ eslint-module-utils@^2.4.1: dependencies: debug "^3.2.7" -"eslint-plugin-flowtype@3.x || 4.x", eslint-plugin-flowtype@4.6.0: +eslint-plugin-flowtype@4.6.0: version "4.6.0" resolved "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz" integrity sha512-W5hLjpFfZyZsXfo5anlu7HM970JBDqbEshAJUkeczP6BFCIfJXuiIBQXyberLRtOStT0OGPF8efeTbxlHk4LpQ== dependencies: lodash "^4.17.15" -eslint-plugin-import@2.20.1, eslint-plugin-import@2.x: +eslint-plugin-import@2.20.1: version "2.20.1" resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz" integrity sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw== @@ -7459,7 +7286,7 @@ eslint-plugin-import@2.20.1, eslint-plugin-import@2.x: read-pkg-up "^2.0.0" resolve "^1.12.0" -eslint-plugin-jsx-a11y@6.2.3, eslint-plugin-jsx-a11y@6.x: +eslint-plugin-jsx-a11y@6.2.3: version "6.2.3" resolved "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz" integrity sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg== @@ -7474,12 +7301,30 @@ eslint-plugin-jsx-a11y@6.2.3, eslint-plugin-jsx-a11y@6.x: has "^1.0.3" jsx-ast-utils "^2.2.1" -eslint-plugin-react-hooks@^1.6.1, "eslint-plugin-react-hooks@1.x || 2.x": +eslint-plugin-react-hooks@^1.6.1: version "1.7.0" resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz" integrity sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA== -eslint-plugin-react@^7.30.1, eslint-plugin-react@7.x: +eslint-plugin-react@7.19.0: + version "7.19.0" + resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz" + integrity sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ== + dependencies: + array-includes "^3.1.1" + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.2.3" + object.entries "^1.1.1" + object.fromentries "^2.0.2" + object.values "^1.1.1" + prop-types "^15.7.2" + resolve "^1.15.1" + semver "^6.3.0" + string.prototype.matchall "^4.0.2" + xregexp "^4.3.0" + +eslint-plugin-react@^7.30.1: version "7.35.0" resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz" integrity sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA== @@ -7503,23 +7348,13 @@ eslint-plugin-react@^7.30.1, eslint-plugin-react@7.x: string.prototype.matchall "^4.0.11" string.prototype.repeat "^1.0.0" -eslint-plugin-react@7.19.0: - version "7.19.0" - resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz" - integrity sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ== +eslint-scope@5.1.1, eslint-scope@^5.0.0: + version "5.1.1" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== dependencies: - array-includes "^3.1.1" - doctrine "^2.1.0" - has "^1.0.3" - jsx-ast-utils "^2.2.3" - object.entries "^1.1.1" - object.fromentries "^2.0.2" - object.values "^1.1.1" - prop-types "^15.7.2" - resolve "^1.15.1" - semver "^6.3.0" - string.prototype.matchall "^4.0.2" - xregexp "^4.3.0" + esrecurse "^4.3.0" + estraverse "^4.1.1" eslint-scope@^4.0.3: version "4.0.3" @@ -7529,14 +7364,6 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@^5.0.0, eslint-scope@5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - eslint-utils@^1.4.3: version "1.4.3" resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz" @@ -7556,7 +7383,7 @@ eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint@*, "eslint@^3 || ^4 || ^5 || ^6", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", "eslint@^5.0.0 || ^6.0.0", eslint@^6.6.0, eslint@^6.8.0, "eslint@>= 4.12.1", eslint@>=6.1.0, "eslint@2.x - 6.x", eslint@6.x: +eslint@^6.6.0, eslint@^6.8.0: version "6.8.0" resolved "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz" integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== @@ -7637,12 +7464,7 @@ esrecurse@^4.1.0, esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^4.2.0: +estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -7761,7 +7583,7 @@ expect@^24.9.0: jest-message-util "^24.9.0" jest-regex-util "^24.9.0" -express@^4.17.1, express@^4.17.3, express@^4.18.2: +express@^4.17.1, express@^4.17.3: version "4.19.2" resolved "https://registry.npmjs.org/express/-/express-4.19.2.tgz" integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== @@ -7855,7 +7677,7 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extsprintf@^1.2.0, extsprintf@1.3.0: +extsprintf@1.3.0, extsprintf@^1.2.0: version "1.3.0" resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz" integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== @@ -7937,14 +7759,6 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" -file-loader@*, file-loader@~6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz" - integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - file-loader@4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/file-loader/-/file-loader-4.3.0.tgz" @@ -7953,6 +7767,14 @@ file-loader@4.3.0: loader-utils "^1.2.3" schema-utils "^2.5.0" +file-loader@~6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz" + integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + file-saver@2.0.5: version "2.0.5" resolved "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz" @@ -8025,6 +7847,14 @@ find-cache-dir@^3.2.0, find-cache-dir@^3.3.1: make-dir "^3.0.2" pkg-dir "^4.1.0" +find-up@4.1.0, find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + find-up@^1.0.0: version "1.1.2" resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz" @@ -8047,14 +7877,6 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" -find-up@^4.0.0, find-up@^4.1.0, find-up@4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - flat-cache@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz" @@ -8241,6 +8063,11 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz" + integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== + fsevents@^1.2.7: version "1.2.13" resolved "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz" @@ -8254,11 +8081,6 @@ fsevents@~2.3.2: resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -fsevents@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz" - integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== - function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" @@ -8318,7 +8140,7 @@ get-caller-file@^1.0.1: resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz" integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== -get-caller-file@^2.0.1, get-caller-file@^2.0.5: +get-caller-file@^2.0.1: version "2.0.5" resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -8339,7 +8161,7 @@ get-own-enumerable-property-symbols@^3.0.0: resolved "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz" integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== -get-stream@^3.0.0, get-stream@3.0.0: +get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz" integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ== @@ -8358,12 +8180,7 @@ get-stream@^5.1.0: dependencies: pump "^3.0.0" -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -get-stream@^6.0.1: +get-stream@^6.0.0, get-stream@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -8389,7 +8206,7 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -gl-matrix@^3.0.0, gl-matrix@^3.2.1, gl-matrix@^3.4.0, gl-matrix@^3.4.3: +gl-matrix@^3.0.0, gl-matrix@^3.4.0, gl-matrix@^3.4.3: version "3.4.3" resolved "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz" integrity sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA== @@ -8467,17 +8284,6 @@ globalthis@^1.0.3: define-properties "^1.2.1" gopd "^1.0.1" -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz" - integrity sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw== - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - globby@8.0.2: version "8.0.2" resolved "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz" @@ -8491,6 +8297,17 @@ globby@8.0.2: pify "^3.0.0" slash "^1.0.0" +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz" + integrity sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw== + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + gopd@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" @@ -8815,17 +8632,6 @@ html-minifier-terser@^6.0.2: relateurl "^0.2.7" terser "^5.10.0" -html-webpack-plugin@^5.5.0: - version "5.6.0" - resolved "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz" - integrity sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw== - dependencies: - "@types/html-minifier-terser" "^6.0.0" - html-minifier-terser "^6.0.2" - lodash "^4.17.21" - pretty-error "^4.0.0" - tapable "^2.0.0" - html-webpack-plugin@4.0.0-beta.11: version "4.0.0-beta.11" resolved "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz" @@ -8838,6 +8644,17 @@ html-webpack-plugin@4.0.0-beta.11: tapable "^1.1.3" util.promisify "1.0.0" +html-webpack-plugin@^5.5.0: + version "5.6.0" + resolved "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz" + integrity sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw== + dependencies: + "@types/html-minifier-terser" "^6.0.0" + html-minifier-terser "^6.0.2" + lodash "^4.17.21" + pretty-error "^4.0.0" + tapable "^2.0.0" + htmlparser2@^6.1.0: version "6.1.0" resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz" @@ -8848,31 +8665,21 @@ htmlparser2@^6.1.0: domutils "^2.5.2" entities "^2.0.0" -http-cache-semantics@^4.0.0: - version "4.1.1" - resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" - integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== - http-cache-semantics@3.8.1: version "3.8.1" resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz" integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== +http-cache-semantics@^4.0.0: + version "4.1.1" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz" integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== -http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz" - integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - http-errors@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" @@ -8884,11 +8691,31 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + http-parser-js@>=0.5.1: version "0.5.8" resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz" integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== +http-proxy-middleware@0.19.1: + version "0.19.1" + resolved "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz" + integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== + dependencies: + http-proxy "^1.17.0" + is-glob "^4.0.0" + lodash "^4.17.11" + micromatch "^3.1.10" + http-proxy-middleware@^2.0.3: version "2.0.6" resolved "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz" @@ -8900,16 +8727,6 @@ http-proxy-middleware@^2.0.3: is-plain-obj "^3.0.0" micromatch "^4.0.2" -http-proxy-middleware@0.19.1: - version "0.19.1" - resolved "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz" - integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== - dependencies: - http-proxy "^1.17.0" - is-glob "^4.0.0" - lodash "^4.17.11" - micromatch "^3.1.10" - http-proxy@^1.17.0, http-proxy@^1.18.1: version "1.18.1" resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz" @@ -8946,7 +8763,7 @@ human-signals@^2.1.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -iconv-lite@^0.4.24, iconv-lite@0.4, iconv-lite@0.4.24: +iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -8999,11 +8816,6 @@ ignore@^4.0.6: resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -image-size@^0.7.4: - version "0.7.5" - resolved "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz" - integrity sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g== - immediate@~3.0.5: version "3.0.6" resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" @@ -9093,7 +8905,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@2, inherits@2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -9113,25 +8925,6 @@ ini@^1.3.5: resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -inquirer@^7.0.0: - version "7.3.3" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - inquirer@7.0.4: version "7.0.4" resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz" @@ -9151,6 +8944,25 @@ inquirer@7.0.4: strip-ansi "^5.1.0" through "^2.3.6" +inquirer@^7.0.0: + version "7.3.3" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.19" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.6.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + internal-ip@^4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz" @@ -9203,7 +9015,7 @@ ip@^1.1.0, ip@^1.1.5: resolved "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz" integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ== -ipaddr.js@^1.9.0: +ipaddr.js@1.9.1, ipaddr.js@^1.9.0: version "1.9.1" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== @@ -9213,11 +9025,6 @@ ipaddr.js@^2.0.1: resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz" integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - is-absolute-url@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz" @@ -9633,21 +9440,14 @@ is-wsl@^1.1.0: resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz" integrity sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw== -is-wsl@^2.1.1: - version "2.2.0" - resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -is-wsl@^2.2.0: +is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== dependencies: is-docker "^2.0.0" -isarray@^1.0.0: +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== @@ -9657,16 +9457,6 @@ isarray@^2.0.5: resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - -isarray@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" @@ -9976,7 +9766,7 @@ jest-resolve-dependencies@^24.9.0: jest-regex-util "^24.3.0" jest-snapshot "^24.9.0" -jest-resolve@*, jest-resolve@^24.9.0, jest-resolve@24.9.0: +jest-resolve@24.9.0, jest-resolve@^24.9.0: version "24.9.0" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz" integrity sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ== @@ -10360,15 +10150,7 @@ jsts@2.7.1: resolved "https://registry.npmjs.org/jsts/-/jsts-2.7.1.tgz" integrity sha512-x2wSZHEBK20CY+Wy+BPE7MrFQHW6sIsdaGUMEqmGAio+3gFzQaBYPwLRonUfQf9Ak8pBieqj9tUofX1+WtAEIg== -jsx-ast-utils@^2.2.1: - version "2.4.1" - resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz" - integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w== - dependencies: - array-includes "^3.1.1" - object.assign "^4.1.0" - -jsx-ast-utils@^2.2.3: +jsx-ast-utils@^2.2.1, jsx-ast-utils@^2.2.3: version "2.4.1" resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz" integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w== @@ -10396,23 +10178,11 @@ jszip@^3.10.1: readable-stream "~2.3.6" setimmediate "^1.0.5" -kdbush@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/kdbush/-/kdbush-3.0.0.tgz" - integrity sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew== - kdbush@^4.0.1, kdbush@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz" integrity sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA== -keyv@^4.0.0: - version "4.5.4" - resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" - integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== - dependencies: - json-buffer "3.0.1" - keyv@3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz" @@ -10420,6 +10190,13 @@ keyv@3.0.0: dependencies: json-buffer "3.0.0" +keyv@^4.0.0: + version "4.5.4" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + killable@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz" @@ -10432,21 +10209,7 @@ kind-of@^2.0.1: dependencies: is-buffer "^1.0.2" -kind-of@^3.0.2: - version "3.2.2" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" - integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== - dependencies: - is-buffer "^1.1.5" - -kind-of@^3.0.3: - version "3.2.2" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" - integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== - dependencies: - is-buffer "^1.1.5" - -kind-of@^3.2.0: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== @@ -10470,11 +10233,6 @@ kleur@^3.0.3: resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -ktx-parse@^0.0.4: - version "0.0.4" - resolved "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.0.4.tgz" - integrity sha512-LY3nrmfXl+wZZdPxgJ3ZmLvG+wkOZZP3/dr4RbQj1Pk3Qwz44esOOSFFVQJcNWpXAtiNIC66WgXufX/SYgYz6A== - last-call-webpack-plugin@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz" @@ -10583,6 +10341,15 @@ loader-runner@^4.2.0: resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz" integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== +loader-utils@1.2.3: + version "1.2.3" + resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: version "1.4.2" resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz" @@ -10601,15 +10368,6 @@ loader-utils@^2.0.0, loader-utils@~2.0.0: emojis-list "^3.0.0" json5 "^2.1.2" -loader-utils@1.2.3: - version "1.2.3" - resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz" - integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== - dependencies: - big.js "^5.2.2" - emojis-list "^2.0.0" - json5 "^1.0.1" - locate-path@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz" @@ -10673,7 +10431,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.5, "lodash@>=3.5 <5": +"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.5: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -10702,6 +10460,11 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" +lowercase-keys@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz" + integrity sha512-RPlX0+PHuvxVDZ7xX+EBVAp4RsVxP/TdDSN2mJYdiq1Lc4Hz7EUSjUI7RZrKKlmrIzVhf6Jo2stj7++gVarS0A== + lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz" @@ -10712,11 +10475,6 @@ lowercase-keys@^2.0.0: resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== -lowercase-keys@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz" - integrity sha512-RPlX0+PHuvxVDZ7xX+EBVAp4RsVxP/TdDSN2mJYdiq1Lc4Hz7EUSjUI7RZrKKlmrIzVhf6Jo2stj7++gVarS0A== - lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" @@ -10731,15 +10489,7 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -make-dir@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -make-dir@^2.1.0: +make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== @@ -10795,7 +10545,7 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" -mapbox-gl@^2.10.0, mapbox-gl@>=1.13.0: +mapbox-gl@^2.10.0: version "2.15.0" resolved "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-2.15.0.tgz" integrity sha512-fjv+aYrd5TIHiL7wRa+W7KjtUqKWziJMZUkK5hm8TvJ3OLeNPx4NmW/DgfYhd/jHej8wWL+QJBDbdMMAKvNC0A== @@ -10823,34 +10573,6 @@ mapbox-gl@^2.10.0, mapbox-gl@>=1.13.0: tinyqueue "^2.0.3" vt-pbf "^3.1.3" -"mapbox-gl@>= 0.47.0 < 2.0.0", "mapbox-gl@>=0.32.1 <2.0.0": - version "1.13.3" - resolved "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-1.13.3.tgz" - integrity sha512-p8lJFEiqmEQlyv+DQxFAOG/XPWN0Wp7j/Psq93Zywz7qt9CcUKFYDBOoOEKzqe6gudHVJY8/Bhqw6VDpX2lSBg== - dependencies: - "@mapbox/geojson-rewind" "^0.5.2" - "@mapbox/geojson-types" "^1.0.2" - "@mapbox/jsonlint-lines-primitives" "^2.0.2" - "@mapbox/mapbox-gl-supported" "^1.5.0" - "@mapbox/point-geometry" "^0.1.0" - "@mapbox/tiny-sdf" "^1.1.1" - "@mapbox/unitbezier" "^0.0.0" - "@mapbox/vector-tile" "^1.3.1" - "@mapbox/whoots-js" "^3.1.0" - csscolorparser "~1.0.3" - earcut "^2.2.2" - geojson-vt "^3.2.1" - gl-matrix "^3.2.1" - grid-index "^1.1.0" - murmurhash-js "^1.0.0" - pbf "^3.2.1" - potpack "^1.0.1" - quickselect "^2.0.0" - rw "^1.3.3" - supercluster "^7.1.0" - tinyqueue "^2.0.3" - vt-pbf "^3.1.1" - marchingsquares@^1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/marchingsquares/-/marchingsquares-1.3.3.tgz" @@ -11006,7 +10728,7 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -"mime-db@>= 1.43.0 < 2", mime-db@1.52.0: +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -11018,16 +10740,16 @@ mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, dependencies: mime-db "1.52.0" -mime@^2.4.4: - version "2.6.0" - resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz" - integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== - mime@1.6.0: version "1.6.0" resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mime@^2.4.4: + version "2.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + mimic-fn@^2.0.0, mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" @@ -11068,13 +10790,6 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - minimatch@3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz" @@ -11082,6 +10797,13 @@ minimatch@3.0.4: dependencies: brace-expansion "^1.1.7" +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz" @@ -11183,16 +10905,16 @@ move-concurrently@^1.0.1: rimraf "^2.5.4" run-queue "^1.0.3" -ms@^2.1.1, ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== +ms@2.1.2, ms@^2.1.1: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + ms@2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" @@ -11239,7 +10961,7 @@ nanoid@^2.0.1: resolved "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz" integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA== -nanoid@^3.1.31, nanoid@^3.3.11: +nanoid@^3.1.31, nanoid@^3.3.11, nanoid@^3.3.7: version "3.3.11" resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz" integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== @@ -11359,17 +11081,7 @@ node-releases@^2.0.18: resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz" integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== -normalize-package-data@^2.3.2: - version "2.5.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-package-data@^2.5.0: +normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -11399,22 +11111,12 @@ normalize-path@^2.1.1: normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz" - integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== - -normalize-url@^3.0.0: - version "3.3.0" - resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz" - integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -normalize-url@^6.0.1: - version "6.1.0" - resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" - integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz" + integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== normalize-url@1.9.1: version "1.9.1" @@ -11435,6 +11137,16 @@ normalize-url@2.0.1: query-string "^5.0.1" sort-keys "^2.0.0" +normalize-url@^3.0.0: + version "3.3.0" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz" + integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz" @@ -12067,7 +11779,7 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -pkg-up@^3.1.0, pkg-up@3.1.0: +pkg-up@3.1.0, pkg-up@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz" integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== @@ -12739,16 +12451,7 @@ postcss-selector-parser@^3.0.0: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-selector-parser@^5.0.0-rc.3: - version "5.0.0" - resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz" - integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== - dependencies: - cssesc "^2.0.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-selector-parser@^5.0.0-rc.4: +postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: version "5.0.0" resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz" integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== @@ -12810,6 +12513,24 @@ postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: indexes-of "^1.0.1" uniq "^1.0.1" +postcss@7.0.21: + version "7.0.21" + resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz" + integrity sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +postcss@8.4.49: + version "8.4.49" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19" + integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA== + dependencies: + nanoid "^3.3.7" + picocolors "^1.1.1" + source-map-js "^1.2.1" + postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.23, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: version "7.0.39" resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz" @@ -12818,7 +12539,7 @@ postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, po picocolors "^0.2.1" source-map "^0.6.1" -postcss@^8.1.0, postcss@^8.4.33: +postcss@^8.4.33: version "8.5.6" resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz" integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== @@ -12827,20 +12548,6 @@ postcss@^8.1.0, postcss@^8.4.33: picocolors "^1.1.1" source-map-js "^1.2.1" -postcss@7.0.21: - version "7.0.21" - resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz" - integrity sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -potpack@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz" - integrity sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ== - potpack@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz" @@ -13019,12 +12726,7 @@ pumpify@^1.3.3: inherits "^2.0.3" pump "^2.0.0" -punycode@^1.2.4: - version "1.4.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz" - integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== - -punycode@^1.4.1: +punycode@^1.2.4, punycode@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz" integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== @@ -13039,6 +12741,13 @@ q@^1.1.2: resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== +qs@6.11.0: + version "6.11.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + qs@^6.12.3: version "6.13.0" resolved "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz" @@ -13051,13 +12760,6 @@ qs@~6.5.2: resolved "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== -qs@6.11.0: - version "6.11.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - query-string@^4.1.0: version "4.3.4" resolved "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz" @@ -13216,7 +12918,7 @@ react-dev-utils@^10.2.1: strip-ansi "6.0.0" text-table "0.2.0" -react-dom@^18.2.0, react-dom@>=16.14.0, react-dom@>=16.3, react-dom@>=16.3.0, react-dom@>=16.6.0, react-dom@>=16.8: +react-dom@^18.2.0: version "18.3.1" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz" integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== @@ -13248,7 +12950,7 @@ react-map-gl-geocoder@^2.2.0: prop-types "^15.7.2" viewport-mercator-project "6.1.1" -react-map-gl@^7.0.16, "react-map-gl@>= 4.0.0": +react-map-gl@^7.0.16: version "7.1.7" resolved "https://registry.npmjs.org/react-map-gl/-/react-map-gl-7.1.7.tgz" integrity sha512-mwjc0obkBJOXCcoXQr3VoLqmqwo9vS4bXfbGsdxXzEgVCv/PM0v+1QggL7W0d/ccIy+VCjbXNlGij+PENz6VNg== @@ -13341,7 +13043,7 @@ react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" -"react@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", react@^18.2.0, react@^18.3.1, react@>=0.14.0, react@>=15.0.0, react@>=16.14.0, react@>=16.3, react@>=16.3.0, react@>=16.6.0, react@>=16.8, react@>=16.8.0: +react@^18.2.0: version "18.3.1" resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz" integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== @@ -13401,7 +13103,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@^2.3.8, readable-stream@~2.3.6, "readable-stream@1 || 2": +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@^2.3.8, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -13498,12 +13200,7 @@ regenerator-runtime@^0.11.0: resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.13.3: - version "0.13.11" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== - -regenerator-runtime@^0.13.4: +regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4: version "0.13.11" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== @@ -13630,7 +13327,7 @@ request-promise-native@^1.0.5: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.34, request@^2.87.0, request@^2.88.0: +request@^2.87.0, request@^2.88.0: version "2.88.2" resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -13743,16 +13440,19 @@ resolve-url@^0.2.1: resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz" integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== -resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.22.4, resolve@^1.3.2, resolve@^1.8.1, resolve@^1.9.0: - version "1.22.8" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" + integrity sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg== + +resolve@1.15.0: + version "1.15.0" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz" + integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw== dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" + path-parse "^1.0.6" -resolve@^1.15.1: +resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.15.1, resolve@^1.22.4, resolve@^1.3.2, resolve@^1.8.1, resolve@^1.9.0: version "1.22.8" resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -13770,17 +13470,12 @@ resolve@^2.0.0-next.5: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@1.1.7: - version "1.1.7" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" - integrity sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg== - -resolve@1.15.0: - version "1.15.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz" - integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw== +responselike@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz" + integrity sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ== dependencies: - path-parse "^1.0.6" + lowercase-keys "^1.0.0" responselike@^2.0.0: version "2.0.1" @@ -13789,13 +13484,6 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" -responselike@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz" - integrity sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ== - dependencies: - lowercase-keys "^1.0.0" - restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz" @@ -13842,7 +13530,7 @@ rgba-regex@^1.0.0: resolved "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz" integrity sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg== -rimraf@^2.5.4, rimraf@^2.6.3, rimraf@2.6.3: +rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.3: version "2.6.3" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -13898,7 +13586,7 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rw@^1.3.3, rw@1: +rw@1, rw@^1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz" integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ== @@ -13910,13 +13598,6 @@ rxjs@^6.5.3, rxjs@^6.6.0: dependencies: tslib "^1.9.0" -rxjs@^7.0.0: - version "7.8.2" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz" - integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== - dependencies: - tslib "^2.1.0" - safe-array-concat@^1.0.0, safe-array-concat@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz" @@ -13927,25 +13608,15 @@ safe-array-concat@^1.0.0, safe-array-concat@^1.1.2: has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@>=5.1.0, safe-buffer@5.2.1: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@~5.1.1: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== safe-regex-test@^1.0.3: version "1.0.3" @@ -13963,7 +13634,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -safer-buffer@^2.0.2, safer-buffer@^2.1.0, "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -13988,13 +13659,6 @@ sanitize.css@^10.0.0: resolved "https://registry.npmjs.org/sanitize.css/-/sanitize.css-10.0.0.tgz" integrity sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg== -sass-loader@^13.0.2: - version "13.3.3" - resolved "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.3.tgz" - integrity sha512-mt5YN2F1MOZr3d/wBRcZxeFgwgkH44wVc2zohO2YF6JiOMkiXe4BYRZpSu2sO1g71mo/j16txzUhsKZlqjVGzA== - dependencies: - neo-async "^2.6.2" - sass-loader@8.0.2: version "8.0.2" resolved "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.2.tgz" @@ -14006,7 +13670,14 @@ sass-loader@8.0.2: schema-utils "^2.6.1" semver "^6.3.0" -sass@^1.3.0, sass@^1.53.0: +sass-loader@^13.0.2: + version "13.3.3" + resolved "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.3.tgz" + integrity sha512-mt5YN2F1MOZr3d/wBRcZxeFgwgkH44wVc2zohO2YF6JiOMkiXe4BYRZpSu2sO1g71mo/j16txzUhsKZlqjVGzA== + dependencies: + neo-async "^2.6.2" + +sass@^1.53.0: version "1.77.8" resolved "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz" integrity sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ== @@ -14057,16 +13728,7 @@ schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1, schema-utils@^2.6 ajv "^6.12.4" ajv-keywords "^3.5.2" -schema-utils@^3.0.0: - version "3.3.0" - resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz" - integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -schema-utils@^3.1.1, schema-utils@^3.2.0: +schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0: version "3.3.0" resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz" integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== @@ -14105,37 +13767,22 @@ selfsigned@^2.1.1: "@types/node-forge" "^1.3.0" node-forge "^1" -semver@^5.4.1, semver@^5.5.0: - version "5.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@^5.5.1: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.7.2" resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^5.6.0: - version "5.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== +semver@6.3.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^6.3.0, semver@6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.2: - version "7.6.3" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - -semver@^7.3.4: +semver@^7.3.2, semver@^7.3.4: version "7.6.3" resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== @@ -14145,11 +13792,6 @@ semver@^7.5.4: resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz" integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== -"semver@2 || 3 || 4 || 5": - version "5.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - send@0.18.0: version "0.18.0" resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" @@ -14288,6 +13930,11 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" +shallowequal@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" @@ -14312,21 +13959,16 @@ shebang-regex@^3.0.0: resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@^1.7.3: - version "1.8.3" - resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz" - integrity sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw== +shell-quote@1.7.2: + version "1.7.2" + resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz" + integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== shell-quote@^1.8.1: version "1.8.1" resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz" integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== -shell-quote@1.7.2: - version "1.7.2" - resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz" - integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== - shellwords@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz" @@ -14430,6 +14072,14 @@ sockjs-client@1.4.0: json3 "^3.3.2" url-parse "^1.4.3" +sockjs@0.3.19: + version "0.3.19" + resolved "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz" + integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== + dependencies: + faye-websocket "^0.10.0" + uuid "^3.0.1" + sockjs@^0.3.24: version "0.3.24" resolved "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz" @@ -14439,14 +14089,6 @@ sockjs@^0.3.24: uuid "^8.3.2" websocket-driver "^0.7.4" -sockjs@0.3.19: - version "0.3.19" - resolved "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz" - integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== - dependencies: - faye-websocket "^0.10.0" - uuid "^3.0.1" - sort-asc@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/sort-asc/-/sort-asc-0.2.0.tgz" @@ -14488,7 +14130,7 @@ source-list-map@^2.0.0: resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -source-map-js@^1.0.2, source-map-js@^1.2.1, "source-map-js@>=0.6.2 <2.0.0": +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2, source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== @@ -14525,25 +14167,15 @@ source-map-url@^0.4.0: resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz" integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== -source-map@^0.5.0: - version "0.5.7" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - -source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1, source-map@0.6.1: +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -spawn-command@^0.0.2-1: - version "0.0.2" - resolved "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz" - integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== +source-map@^0.5.0, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== spdx-correct@^3.0.0: version "3.2.0" @@ -14661,16 +14293,16 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.4.0 < 2": - version "1.5.0" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - statuses@2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + stealthy-require@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz" @@ -14713,13 +14345,6 @@ strict-uri-encode@^1.0.0: resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz" integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== -string_decoder@^1.0.0, string_decoder@^1.1.1, string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - string-length@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz" @@ -14753,16 +14378,7 @@ string-width@^2.0.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^3.1.0: +string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz" integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== @@ -14771,7 +14387,7 @@ string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +string-width@^4.1.0: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -14834,6 +14450,13 @@ string.prototype.trimstart@^1.0.8: define-properties "^1.2.1" es-object-atoms "^1.0.0" +string_decoder@^1.0.0, string_decoder@^1.1.1, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + stringify-object@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz" @@ -14843,6 +14466,13 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" +strip-ansi@6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" @@ -14869,14 +14499,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^5.0.1" - -strip-ansi@6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" + ansi-regex "^5.0.1" strip-bom@^3.0.0: version "3.0.0" @@ -14913,11 +14536,6 @@ strip-json-comments@^3.0.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -style-loader@^3.3.1: - version "3.3.4" - resolved "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz" - integrity sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w== - style-loader@0.23.1: version "0.23.1" resolved "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz" @@ -14926,6 +14544,26 @@ style-loader@0.23.1: loader-utils "^1.1.0" schema-utils "^1.0.0" +style-loader@^3.3.1: + version "3.3.4" + resolved "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz" + integrity sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w== + +styled-components@^6.3.9: + version "6.3.9" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.3.9.tgz#b03c36606e7fa449028af1433d86a849ab289931" + integrity sha512-J72R4ltw0UBVUlEjTzI0gg2STOqlI9JBhQOL4Dxt7aJOnnSesy0qJDn4PYfMCafk9cWOaVg129Pesl5o+DIh0Q== + dependencies: + "@emotion/is-prop-valid" "1.4.0" + "@emotion/unitless" "0.10.0" + "@types/stylis" "4.2.7" + css-to-react-native "3.2.0" + csstype "3.2.3" + postcss "8.4.49" + shallowequal "1.1.0" + stylis "4.3.6" + tslib "2.8.1" + stylehacks@^4.0.0: version "4.0.3" resolved "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz" @@ -14935,6 +14573,11 @@ stylehacks@^4.0.0: postcss "^7.0.0" postcss-selector-parser "^3.0.0" +stylis@4.3.6: + version "4.3.6" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.6.tgz#7c7b97191cb4f195f03ecab7d52f7902ed378320" + integrity sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ== + subtag@^0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/subtag/-/subtag-0.5.0.tgz" @@ -14948,13 +14591,6 @@ suggestions@^1.6.0: fuzzy "^0.1.1" xtend "^4.0.0" -supercluster@^7.1.0: - version "7.1.5" - resolved "https://registry.npmjs.org/supercluster/-/supercluster-7.1.5.tgz" - integrity sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg== - dependencies: - kdbush "^3.0.0" - supercluster@^8.0.0: version "8.0.1" resolved "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz" @@ -14981,14 +14617,7 @@ supports-color@^6.1.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0: - version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^7.1.0: +supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -15002,13 +14631,6 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" -supports-color@^8.1.0: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" @@ -15078,6 +14700,21 @@ tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== +terser-webpack-plugin@2.3.5: + version "2.3.5" + resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.5.tgz" + integrity sha512-WlWksUoq+E4+JlJ+h+U+QUzXpcsMSSNXkDy9lBVkSqDn1w23Gg29L/ary9GeJVYCGiNJJX7LnVc4bwL1N3/g1w== + dependencies: + cacache "^13.0.1" + find-cache-dir "^3.2.0" + jest-worker "^25.1.0" + p-limit "^2.2.2" + schema-utils "^2.6.4" + serialize-javascript "^2.1.2" + source-map "^0.6.1" + terser "^4.4.3" + webpack-sources "^1.4.3" + terser-webpack-plugin@^1.4.3: version "1.4.6" resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.6.tgz" @@ -15104,31 +14741,7 @@ terser-webpack-plugin@^5.3.10: serialize-javascript "^6.0.1" terser "^5.26.0" -terser-webpack-plugin@2.3.5: - version "2.3.5" - resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.5.tgz" - integrity sha512-WlWksUoq+E4+JlJ+h+U+QUzXpcsMSSNXkDy9lBVkSqDn1w23Gg29L/ary9GeJVYCGiNJJX7LnVc4bwL1N3/g1w== - dependencies: - cacache "^13.0.1" - find-cache-dir "^3.2.0" - jest-worker "^25.1.0" - p-limit "^2.2.2" - schema-utils "^2.6.4" - serialize-javascript "^2.1.2" - source-map "^0.6.1" - terser "^4.4.3" - webpack-sources "^1.4.3" - -terser@^4.1.2, terser@^4.6.3: - version "4.8.1" - resolved "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz" - integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - -terser@^4.4.3: +terser@^4.1.2, terser@^4.4.3, terser@^4.6.3: version "4.8.1" resolved "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz" integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw== @@ -15157,29 +14770,16 @@ test-exclude@^5.2.3: read-pkg-up "^4.0.0" require-main-filename "^2.0.0" -text-table@^0.2.0, text-table@0.2.0: +text-table@0.2.0, text-table@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -texture-compressor@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/texture-compressor/-/texture-compressor-1.0.2.tgz" - integrity sha512-dStVgoaQ11mA5htJ+RzZ51ZxIZqNOgWKAIvtjLrW1AliQQLCmrDqNzQZ8Jh91YealQ95DXt4MEduLzJmbs6lig== - dependencies: - argparse "^1.0.10" - image-size "^0.7.4" - throat@^4.0.0: version "4.1.0" resolved "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz" integrity sha512-wCVxLDcFxw7ujDxaeJC6nfl2XfHJNYs8yUYJnvMgtPEFlttP9tHSfRUv2vBe6C4hkVFPWoP1P6ZccbYjmSEkKA== -through@^2.3.6: - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - through2@^2.0.0: version "2.0.5" resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" @@ -15188,6 +14788,11 @@ through2@^2.0.0: readable-stream "~2.3.6" xtend "~4.0.1" +through@^2.3.6: + version "2.3.8" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + thunky@^1.0.2: version "1.1.0" resolved "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz" @@ -15303,36 +14908,26 @@ tr46@^1.0.1: dependencies: punycode "^2.1.0" -tree-kill@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz" - integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== - trim-newlines@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -ts-pnp@^1.1.6, ts-pnp@1.1.6: +ts-pnp@1.1.6, ts-pnp@^1.1.6: version "1.1.6" resolved "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz" integrity sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ== -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@2.8.1, tslib@^2.0.3, tslib@^2.4.0, tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== -tslib@^1.9.0: +tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.8.1: - version "2.8.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" - integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== - tsutils@^3.17.1: version "3.21.0" resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" @@ -15446,11 +15041,6 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript@^3.2.1, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta": - version "3.9.10" - resolved "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz" - integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== - typewise-core@^1.2, typewise-core@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/typewise-core/-/typewise-core-1.2.0.tgz" @@ -15555,7 +15145,7 @@ universalify@^0.1.0: resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== -unpipe@~1.0.0, unpipe@1.0.0: +unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -15598,15 +15188,6 @@ urix@^0.1.0: resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz" integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== -url-loader@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz" - integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== - dependencies: - loader-utils "^2.0.0" - mime-types "^2.1.27" - schema-utils "^3.0.0" - url-loader@2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/url-loader/-/url-loader-2.3.0.tgz" @@ -15616,6 +15197,15 @@ url-loader@2.3.0: mime "^2.4.4" schema-utils "^2.5.0" +url-loader@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz" + integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== + dependencies: + loader-utils "^2.0.0" + mime-types "^2.1.27" + schema-utils "^3.0.0" + url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz" @@ -15654,6 +15244,14 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +util.promisify@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz" + integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + util.promisify@^1.0.0: version "1.1.2" resolved "https://registry.npmjs.org/util.promisify/-/util.promisify-1.1.2.tgz" @@ -15677,13 +15275,12 @@ util.promisify@~1.0.0: has-symbols "^1.0.1" object.getownpropertydescriptors "^2.1.0" -util.promisify@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz" - integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== +util@0.10.3: + version "0.10.3" + resolved "https://registry.npmjs.org/util/-/util-0.10.3.tgz" + integrity sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ== dependencies: - define-properties "^1.1.2" - object.getownpropertydescriptors "^2.0.3" + inherits "2.0.1" util@^0.11.0: version "0.11.1" @@ -15692,13 +15289,6 @@ util@^0.11.0: dependencies: inherits "2.0.3" -util@0.10.3: - version "0.10.3" - resolved "https://registry.npmjs.org/util/-/util-0.10.3.tgz" - integrity sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ== - dependencies: - inherits "2.0.1" - utila@~0.4: version "0.4.0" resolved "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz" @@ -15764,7 +15354,7 @@ vm-browserify@^1.0.1: resolved "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -vt-pbf@^3.1.1, vt-pbf@^3.1.3: +vt-pbf@^3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz" integrity sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA== @@ -15841,7 +15431,7 @@ webidl-conversions@^4.0.2: resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== -webpack-cli@^4.9.2, webpack-cli@4.x.x: +webpack-cli@^4.9.2: version "4.10.0" resolved "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz" integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== @@ -15881,42 +15471,6 @@ webpack-dev-middleware@^5.3.4: range-parser "^1.2.1" schema-utils "^4.0.0" -webpack-dev-server@^4.7.4: - version "4.15.2" - resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz" - integrity sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g== - dependencies: - "@types/bonjour" "^3.5.9" - "@types/connect-history-api-fallback" "^1.3.5" - "@types/express" "^4.17.13" - "@types/serve-index" "^1.9.1" - "@types/serve-static" "^1.13.10" - "@types/sockjs" "^0.3.33" - "@types/ws" "^8.5.5" - ansi-html-community "^0.0.8" - bonjour-service "^1.0.11" - chokidar "^3.5.3" - colorette "^2.0.10" - compression "^1.7.4" - connect-history-api-fallback "^2.0.0" - default-gateway "^6.0.3" - express "^4.17.3" - graceful-fs "^4.2.6" - html-entities "^2.3.2" - http-proxy-middleware "^2.0.3" - ipaddr.js "^2.0.1" - launch-editor "^2.6.0" - open "^8.0.9" - p-retry "^4.5.0" - rimraf "^3.0.2" - schema-utils "^4.0.0" - selfsigned "^2.1.1" - serve-index "^1.9.1" - sockjs "^0.3.24" - spdy "^4.0.2" - webpack-dev-middleware "^5.3.4" - ws "^8.13.0" - webpack-dev-server@3.10.3: version "3.10.3" resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.10.3.tgz" @@ -15956,6 +15510,42 @@ webpack-dev-server@3.10.3: ws "^6.2.1" yargs "12.0.5" +webpack-dev-server@^4.7.4: + version "4.15.2" + resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz" + integrity sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g== + dependencies: + "@types/bonjour" "^3.5.9" + "@types/connect-history-api-fallback" "^1.3.5" + "@types/express" "^4.17.13" + "@types/serve-index" "^1.9.1" + "@types/serve-static" "^1.13.10" + "@types/sockjs" "^0.3.33" + "@types/ws" "^8.5.5" + ansi-html-community "^0.0.8" + bonjour-service "^1.0.11" + chokidar "^3.5.3" + colorette "^2.0.10" + compression "^1.7.4" + connect-history-api-fallback "^2.0.0" + default-gateway "^6.0.3" + express "^4.17.3" + graceful-fs "^4.2.6" + html-entities "^2.3.2" + http-proxy-middleware "^2.0.3" + ipaddr.js "^2.0.1" + launch-editor "^2.6.0" + open "^8.0.9" + p-retry "^4.5.0" + rimraf "^3.0.2" + schema-utils "^4.0.0" + selfsigned "^2.1.1" + serve-index "^1.9.1" + sockjs "^0.3.24" + spdy "^4.0.2" + webpack-dev-middleware "^5.3.4" + ws "^8.13.0" + webpack-log@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz" @@ -15996,7 +15586,7 @@ webpack-sources@^3.2.3: resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -"webpack@^2.0.0 || ^3.0.0 || ^4.0.0", webpack@^4.0.0, "webpack@^4.36.0 || ^5.0.0", webpack@^4.4.0, "webpack@2 || 3 || 4", webpack@4.42.0: +webpack@4.42.0: version "4.42.0" resolved "https://registry.npmjs.org/webpack/-/webpack-4.42.0.tgz" integrity sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w== @@ -16025,7 +15615,7 @@ webpack-sources@^3.2.3: watchpack "^1.6.0" webpack-sources "^1.4.1" -"webpack@^4 || ^5", "webpack@^4.0.0 || ^5.0.0", "webpack@^4.37.0 || ^5.0.0", webpack@^5.0.0, webpack@^5.1.0, webpack@^5.20.0, webpack@^5.70.0, webpack@^5.72.1, webpack@>=2, "webpack@4.x.x || 5.x.x": +webpack@^5.70.0: version "5.94.0" resolved "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz" integrity sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg== @@ -16054,7 +15644,7 @@ webpack-sources@^3.2.3: watchpack "^2.4.1" webpack-sources "^3.2.3" -websocket-driver@^0.7.4, websocket-driver@>=0.5.1: +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: version "0.7.4" resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz" integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== @@ -16348,15 +15938,6 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" @@ -16385,14 +15966,7 @@ ws@^5.2.0: dependencies: async-limiter "~1.0.0" -ws@^6.1.2: - version "6.2.3" - resolved "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz" - integrity sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA== - dependencies: - async-limiter "~1.0.0" - -ws@^6.2.1: +ws@^6.1.2, ws@^6.2.1: version "6.2.3" resolved "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz" integrity sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA== @@ -16431,11 +16005,6 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz" integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - yallist@^3.0.2: version "3.1.1" resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" @@ -16472,40 +16041,6 @@ yargs-parser@^20.2.3: resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - -yargs@^13.3.0: - version "13.3.2" - resolved "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - -yargs@^17.3.1: - version "17.7.2" - resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - yargs@12.0.5: version "12.0.5" resolved "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz" @@ -16523,3 +16058,19 @@ yargs@12.0.5: which-module "^2.0.0" y18n "^3.2.1 || ^4.0.0" yargs-parser "^11.1.1" + +yargs@^13.3.0: + version "13.3.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2"