From 7fbd4ef9daa910fc7c63d5e30a56954cc3b7450a Mon Sep 17 00:00:00 2001 From: lhawkins Date: Thu, 19 Mar 2026 15:59:03 -0400 Subject: [PATCH 01/37] feat: Add lasso select tool button to map controls Add LassoIcon SVG and lasso toggle button to MapControls component with onLassoToggle/isLassoActive props. Wire up placeholder handlers in both the Multi map and standalone GeoSetLayer views. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/GeoSetMultiMap/Multi.tsx | 2 ++ .../src/components/MapControls.tsx | 31 +++++++++++++++++++ .../src/layers/GeoSetLayer/GeoSetLayer.tsx | 4 +++ 3 files changed, 37 insertions(+) diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx index 56f242f7b9..7f2763f120 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx @@ -1054,6 +1054,8 @@ const DeckMulti = (props: DeckMultiProps) => { onResetView={handleResetView} onRulerToggle={handleRulerToggle} isRulerActive={measureState.isActive} + onLassoToggle={() => {}} + isLassoActive={false} position="top-right" /> {clickedFeature && ( diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx index df540c2886..8fa06dc599 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx @@ -25,6 +25,8 @@ export type MapControlsProps = { onResetView: () => void; onRulerToggle: () => void; isRulerActive: boolean; + onLassoToggle: () => void; + isLassoActive: boolean; position?: 'top-left' | 'top-right'; }; @@ -120,12 +122,32 @@ const RulerIcon = () => ( ); +const LassoIcon = () => ( + + {/* Lasso rope loop — open at bottom-right leading into cursor */} + + {/* Solid cursor arrow pointing lower-right */} + + +); + const MapControls = ({ onZoomIn, onZoomOut, onResetView, onRulerToggle, isRulerActive, + onLassoToggle, + isLassoActive, position = 'top-left', }: MapControlsProps) => ( @@ -146,6 +168,15 @@ const MapControls = ({ > + + + ); diff --git a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx index 659014ca9d..774158b1d3 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx @@ -1227,6 +1227,10 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { onRulerToggle={handleRulerToggle} isRulerActive={measureState.isActive} position="top-right" + onLassoToggle={function (): void { + throw new Error('Function not implemented.'); + }} + isLassoActive={false} /> Date: Thu, 19 Mar 2026 17:28:37 -0400 Subject: [PATCH 02/37] feat: Wire up lasso select tool with layer picker dropdown Connect the lasso button in MapControls to actual state management in Multi.tsx. Clicking the lasso button now opens a dropdown listing all map layers; selecting a layer activates lasso mode for that layer. Includes styled dropdown panel with outside-click dismissal. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/GeoSetMultiMap/Multi.tsx | 35 +++- .../src/components/MapControls.tsx | 189 +++++++++++++++--- wiki/Development-Guide.md | 2 +- 3 files changed, 191 insertions(+), 35 deletions(-) diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx index c175dbc72a..4525dc90ea 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx @@ -879,6 +879,18 @@ const DeckMulti = (props: DeckMultiProps) => { [sortedLayers, layerVisibility], ); + // Layer list for lasso layer picker dropdown + const lassoLayers = useMemo( + () => + sortedLayers.map(entry => ({ + id: String(entry.sliceId), + name: + (entry.legendEntry.sliceName as string | undefined) || + entry.legendEntry.legendName, + })), + [sortedLayers], + ); + // Build legendsBySlice for MultiLegend component, with category enabled state applied. // Merges loaded entries with stub entries so the legend shows all layers immediately. const legendsBySlice: Record = useMemo(() => { @@ -998,6 +1010,22 @@ const DeckMulti = (props: DeckMultiProps) => { // Keep ref in sync with measure state for use in callbacks measureActiveRef.current = measureState.isActive; + // Lasso selection state + const [lassoIsActive, setLassoIsActive] = useState(false); + const [activeLassoLayerId, setActiveLassoLayerId] = useState< + string | undefined + >(); + + const handleLassoToggle = useCallback(() => { + setLassoIsActive(false); + setActiveLassoLayerId(undefined); + }, []); + + const handleLassoLayerSelect = useCallback((layerId: string) => { + setActiveLassoLayerId(layerId); + setLassoIsActive(true); + }, []); + const handleRulerToggle = useCallback(() => { setMeasureState(prev => { if (prev.isActive) { @@ -1138,8 +1166,11 @@ const DeckMulti = (props: DeckMultiProps) => { onResetView={handleResetView} onRulerToggle={handleRulerToggle} isRulerActive={measureState.isActive} - onLassoToggle={() => {}} - isLassoActive={false} + onLassoToggle={handleLassoToggle} + isLassoActive={lassoIsActive} + lassoLayers={lassoLayers} + activeLassoLayerId={activeLassoLayerId} + onLassoLayerSelect={handleLassoLayerSelect} position="top-right" /> {clickedFeature && ( diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx index 8fa06dc599..632444fb47 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx @@ -16,9 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -import { memo } from 'react'; +import { memo, useState, useRef, useEffect } from 'react'; import { styled } from '@superset-ui/core'; +export type LassoLayer = { id: string; name: string }; + export type MapControlsProps = { onZoomIn: () => void; onZoomOut: () => void; @@ -27,6 +29,9 @@ export type MapControlsProps = { isRulerActive: boolean; onLassoToggle: () => void; isLassoActive: boolean; + lassoLayers?: LassoLayer[]; + activeLassoLayerId?: string; + onLassoLayerSelect?: (layerId: string) => void; position?: 'top-left' | 'top-right'; }; @@ -87,6 +92,68 @@ const ControlButton = styled.button<{ $isActive?: boolean }>( `, ); +const DropdownPanel = styled.div( + ({ theme }) => ` + position: absolute; + top: calc(100% + 6px); + right: 0; + min-width: 180px; + background: ${theme.colorBgElevated}; + border: 1px solid ${theme.colorBorderSecondary}; + border-radius: 6px; + box-shadow: 0 4px 12px ${theme.colorText}1F; + overflow: hidden; +`, +); + +const DropdownHeader = styled.div( + ({ theme }) => ` + padding: 8px 12px 6px; + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + color: ${theme.colorTextSecondary}; + border-bottom: 1px solid ${theme.colorBorderSecondary}; +`, +); + +const DropdownItem = styled.button<{ $isActive?: boolean }>( + ({ theme, $isActive }) => ` + display: flex; + align-items: center; + gap: 8px; + width: 100%; + padding: 8px 12px; + background: ${$isActive ? theme.colorPrimaryBg : 'transparent'}; + border: none; + cursor: pointer; + font-family: inherit; + font-size: 13px; + color: ${$isActive ? theme.colorPrimary : theme.colorText}; + text-align: left; + white-space: nowrap; + + &:hover { + background: ${$isActive ? theme.colorPrimaryBgHover : theme.colorBgTextHover}; + } +`, +); + +const CheckIcon = () => ( + + + +); + const HomeIcon = () => ( ( - - - - - - - − - - - + - - - - - - - - - -); +}: MapControlsProps) => { + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + const containerRef = useRef(null); + + // Close dropdown on outside click + useEffect(() => { + if (!isDropdownOpen) return undefined; + const handleOutsideClick = (e: MouseEvent) => { + if ( + containerRef.current && + !containerRef.current.contains(e.target as Node) + ) { + setIsDropdownOpen(false); + } + }; + document.addEventListener('mousedown', handleOutsideClick); + return () => document.removeEventListener('mousedown', handleOutsideClick); + }, [isDropdownOpen]); + + const handleLassoButtonClick = () => { + if (isLassoActive) { + // Deactivate lasso + onLassoToggle(); + setIsDropdownOpen(false); + } else { + // Open layer picker + setIsDropdownOpen(prev => !prev); + } + }; + + const handleLayerSelect = (layerId: string) => { + setIsDropdownOpen(false); + onLassoLayerSelect?.(layerId); + }; + + return ( + + + + + + + − + + + + + + + + + + + + + + {isDropdownOpen && lassoLayers.length > 0 && ( + + Select layer + {lassoLayers.map(layer => ( + handleLayerSelect(layer.id)} + > + {layer.id === activeLassoLayerId && } + {layer.id !== activeLassoLayerId && ( + + )} + {layer.name} + + ))} + + )} + + ); +}; export default memo(MapControls); diff --git a/wiki/Development-Guide.md b/wiki/Development-Guide.md index 42a9b9a730..f5fea97569 100644 --- a/wiki/Development-Guide.md +++ b/wiki/Development-Guide.md @@ -118,7 +118,7 @@ Each phase checks a staleness flag before proceeding. When the user changes a fi | `utils/fitViewport.ts` | Autozoom calculation to fit features in the viewport | | `utils/liveViewportStore.ts` | Module-level store for live viewport state (bypasses Redux to avoid "Altered" chart state) | | `components/MultiLegend.tsx` | Drag-and-drop multi-layer legend with toggle/isolate | -| `components/MapControls.tsx` | Measurement tool and zoom controls | +| `components/MapControls.tsx` | Zoom controls, measurement tool, and lasso select tool | ## Branch Strategy From 09c7a1ffd65edf77e92fe022640e2ac27aac7e4a Mon Sep 17 00:00:00 2001 From: lhawkins Date: Fri, 20 Mar 2026 12:23:27 -0400 Subject: [PATCH 03/37] feat: Increase lasso select icon size for better visibility Bump LassoIcon SVG dimensions from 16x16 to 18x18 to improve visual consistency with other map control icons. Update wiki to document the lasso select tool in the feature comparison table. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../plugins/geoset-map-chart/src/components/MapControls.tsx | 2 +- wiki/Home.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx index 632444fb47..146b4d5765 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx @@ -190,7 +190,7 @@ const RulerIcon = () => ( ); const LassoIcon = () => ( - + {/* Lasso rope loop — open at bottom-right leading into cursor */} Date: Mon, 23 Mar 2026 12:21:27 -0400 Subject: [PATCH 04/37] feat: Add library-based lasso drawing with freehand/polygon modes Integrate @deck.gl-community/editable-layers for proper lasso polygon drawing, replacing placeholder wiring. Users can now switch between freehand (drag) and click-to-draw polygon modes. Multi-layer charts support checkbox-based layer selection for lasso targets. Adds MapControls unit tests. Co-Authored-By: Claude Opus 4.6 (1M context) --- superset-frontend/package-lock.json | 2674 ++++++++++++++--- .../plugins/geoset-map-chart/package.json | 1 + .../geoset-map-chart/src/DeckGLContainer.tsx | 61 +- .../src/GeoSetMultiMap/Multi.tsx | 76 +- .../src/components/LassoOverlay.tsx | 111 + .../src/components/MapControls.tsx | 217 +- .../src/layers/GeoSetLayer/GeoSetLayer.tsx | 31 +- .../test/components/MapControls.test.tsx | 198 ++ superset-frontend/webpack.config.js | 2 +- 9 files changed, 2900 insertions(+), 471 deletions(-) create mode 100644 superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx create mode 100644 superset-frontend/plugins/geoset-map-chart/test/components/MapControls.test.tsx diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 132d28a098..fb7eb02242 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -3858,6 +3858,23 @@ "ms": "^2.1.1" } }, + "node_modules/@deck.gl-community/layers": { + "version": "9.2.8", + "resolved": "https://registry.npmjs.org/@deck.gl-community/layers/-/layers-9.2.8.tgz", + "integrity": "sha512-R2EJy5CgS7fByDBxcz88Ci017jqXjj6OpznhS5eGfzhVhutk+paH9mHJFDvwQCLtqI0Ko90o34nBFO17bxqEKw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@deck.gl/core": "~9.2.8", + "@deck.gl/layers": "~9.2.8", + "@deck.gl/mesh-layers": "~9.2.8", + "@luma.gl/constants": "~9.2.6", + "@luma.gl/core": "~9.2.6", + "@luma.gl/engine": "~9.2.6", + "@luma.gl/shadertools": "~9.2.6", + "@math.gl/core": "^4.0.0" + } + }, "node_modules/@deck.gl/aggregation-layers": { "version": "9.2.5", "resolved": "https://registry.npmjs.org/@deck.gl/aggregation-layers/-/aggregation-layers-9.2.5.tgz", @@ -3878,25 +3895,25 @@ } }, "node_modules/@deck.gl/core": { - "version": "9.2.5", - "resolved": "https://registry.npmjs.org/@deck.gl/core/-/core-9.2.5.tgz", - "integrity": "sha512-/PGNX4Wd7rEahYi6ivC4WExJ3U6Hqgl42R83guNzTL6gM2+02PUQRoQG9QdFagj5d6kWYVN0LVJME2a5WQmzOg==", - "license": "MIT", - "dependencies": { - "@loaders.gl/core": "^4.2.0", - "@loaders.gl/images": "^4.2.0", - "@luma.gl/constants": "^9.2.4", - "@luma.gl/core": "^9.2.4", - "@luma.gl/engine": "^9.2.4", - "@luma.gl/shadertools": "^9.2.4", - "@luma.gl/webgl": "^9.2.4", + "version": "9.2.11", + "resolved": "https://registry.npmjs.org/@deck.gl/core/-/core-9.2.11.tgz", + "integrity": "sha512-lpdxXQuFSkd6ET7M6QxPI8QMhsLRY6vzLyk83sPGFb7JSb4OhrNHYt9sfIhcA/hxJW7bdBSMWWphf2GvQetVuA==", + "license": "MIT", + "dependencies": { + "@loaders.gl/core": "~4.3.4", + "@loaders.gl/images": "~4.3.4", + "@luma.gl/constants": "~9.2.6", + "@luma.gl/core": "~9.2.6", + "@luma.gl/engine": "~9.2.6", + "@luma.gl/shadertools": "~9.2.6", + "@luma.gl/webgl": "~9.2.6", "@math.gl/core": "^4.1.0", "@math.gl/sun": "^4.1.0", "@math.gl/types": "^4.1.0", "@math.gl/web-mercator": "^4.1.0", - "@probe.gl/env": "^4.1.0", - "@probe.gl/log": "^4.1.0", - "@probe.gl/stats": "^4.1.0", + "@probe.gl/env": "^4.1.1", + "@probe.gl/log": "^4.1.1", + "@probe.gl/stats": "^4.1.1", "@types/offscreencanvas": "^2019.6.4", "gl-matrix": "^3.0.0", "mjolnir.js": "^3.0.0" @@ -3953,14 +3970,14 @@ } }, "node_modules/@deck.gl/layers": { - "version": "9.2.5", - "resolved": "https://registry.npmjs.org/@deck.gl/layers/-/layers-9.2.5.tgz", - "integrity": "sha512-a48zWxeHknSX67ZeIzWeLXuOVJkEnQjnLIC27Uv3zHjKlvaoraWPOgScUNyteB0UIIzhzE+D8lF+ViHeIdkNSA==", + "version": "9.2.11", + "resolved": "https://registry.npmjs.org/@deck.gl/layers/-/layers-9.2.11.tgz", + "integrity": "sha512-2FSb0Qa6YR+Rg6GWhYOGTUug3vtZ4uKcFdnrdiJoVXGyibKJMScKZIsivY0r/yQQZsaBjYqty5QuVJvdtEHxSA==", "license": "MIT", "dependencies": { - "@loaders.gl/images": "^4.2.0", - "@loaders.gl/schema": "^4.2.0", - "@luma.gl/shadertools": "^9.2.4", + "@loaders.gl/images": "~4.3.4", + "@loaders.gl/schema": "~4.3.4", + "@luma.gl/shadertools": "~9.2.6", "@mapbox/tiny-sdf": "^2.0.5", "@math.gl/core": "^4.1.0", "@math.gl/polygon": "^4.1.0", @@ -3969,28 +3986,28 @@ }, "peerDependencies": { "@deck.gl/core": "~9.2.0", - "@loaders.gl/core": "^4.2.0", - "@luma.gl/core": "~9.2.4", - "@luma.gl/engine": "~9.2.4" + "@loaders.gl/core": "~4.3.4", + "@luma.gl/core": "~9.2.6", + "@luma.gl/engine": "~9.2.6" } }, "node_modules/@deck.gl/mesh-layers": { - "version": "9.2.5", - "resolved": "https://registry.npmjs.org/@deck.gl/mesh-layers/-/mesh-layers-9.2.5.tgz", - "integrity": "sha512-OJ7Nx6xhp7+bQ4S4asUUp7PdGwcfmQpQhe5SHDGy1UBZ0yZE+ojOo9uvVfXvGBnqq4Zpg9avV+WRN1/BffBsOw==", + "version": "9.2.11", + "resolved": "https://registry.npmjs.org/@deck.gl/mesh-layers/-/mesh-layers-9.2.11.tgz", + "integrity": "sha512-zPB7TtnPXB3tOEoOfcOkNZo7coIq/ukIQa8HIUQLLiOE8AVSQfz3kbMmMK6rUabXlQbgSw/I/j3kFSYRHg3NGg==", "license": "MIT", "dependencies": { - "@loaders.gl/gltf": "^4.2.0", - "@loaders.gl/schema": "^4.2.0", - "@luma.gl/gltf": "^9.2.4", - "@luma.gl/shadertools": "^9.2.4" + "@loaders.gl/gltf": "~4.3.4", + "@loaders.gl/schema": "~4.3.4", + "@luma.gl/gltf": "~9.2.6", + "@luma.gl/shadertools": "~9.2.6" }, "peerDependencies": { "@deck.gl/core": "~9.2.0", - "@luma.gl/core": "~9.2.4", - "@luma.gl/engine": "~9.2.4", - "@luma.gl/gltf": "~9.2.4", - "@luma.gl/shadertools": "~9.2.4" + "@luma.gl/core": "~9.2.6", + "@luma.gl/engine": "~9.2.6", + "@luma.gl/gltf": "~9.2.6", + "@luma.gl/shadertools": "~9.2.6" } }, "node_modules/@deck.gl/react": { @@ -7797,15 +7814,15 @@ } }, "node_modules/@luma.gl/constants": { - "version": "9.2.5", - "resolved": "https://registry.npmjs.org/@luma.gl/constants/-/constants-9.2.5.tgz", - "integrity": "sha512-Z+DC7LIw+kPcIthGJdSoquIc92kkUlTOINMuJtssPsvOgFYtlsRn29h95K9y8ehjh234q2+73ExjfDQFE64f5Q==", + "version": "9.2.6", + "resolved": "https://registry.npmjs.org/@luma.gl/constants/-/constants-9.2.6.tgz", + "integrity": "sha512-rvFFrJuSm5JIWbDHFuR4Q2s4eudO3Ggsv0TsGKn9eqvO7bBiPm/ANugHredvh3KviEyYuMZZxtfJvBdr3kzldg==", "license": "MIT" }, "node_modules/@luma.gl/core": { - "version": "9.2.5", - "resolved": "https://registry.npmjs.org/@luma.gl/core/-/core-9.2.5.tgz", - "integrity": "sha512-7tQ6wTTtQV6iWZxjMr+BDzS2o814EvaNW5efKtdzdvbbNyDWkDQZkyHkPvgGBB1o/+N2cbZS7GWyxOljCCH5uA==", + "version": "9.2.6", + "resolved": "https://registry.npmjs.org/@luma.gl/core/-/core-9.2.6.tgz", + "integrity": "sha512-d8KcH8ZZcjDAodSN/G2nueA9YE2X8kMz7Q0OxDGpCww6to1MZXM3Ydate/Jqsb5DDKVgUF6yD6RL8P5jOki9Yw==", "license": "MIT", "dependencies": { "@math.gl/types": "^4.1.0", @@ -7816,9 +7833,9 @@ } }, "node_modules/@luma.gl/engine": { - "version": "9.2.5", - "resolved": "https://registry.npmjs.org/@luma.gl/engine/-/engine-9.2.5.tgz", - "integrity": "sha512-swM+4VO+ab4DU58TB+cdSdby/MGLLWA9ez6BmaZ0HZwLN1HNdYwbQmT71Frtw+6lJpmBZHr78KOQi66Zx5+SOg==", + "version": "9.2.6", + "resolved": "https://registry.npmjs.org/@luma.gl/engine/-/engine-9.2.6.tgz", + "integrity": "sha512-1AEDs2AUqOWh7Wl4onOhXmQF+Rz1zNdPXF+Kxm4aWl92RQ42Sh2CmTvRt2BJku83VQ91KFIEm/v3qd3Urzf+Uw==", "license": "MIT", "dependencies": { "@math.gl/core": "^4.1.0", @@ -7832,9 +7849,9 @@ } }, "node_modules/@luma.gl/gltf": { - "version": "9.2.5", - "resolved": "https://registry.npmjs.org/@luma.gl/gltf/-/gltf-9.2.5.tgz", - "integrity": "sha512-hQFwtgKK4Vnd6t2bqlKVX+Z+Q5gCimq3V9LCiQmQ6An3t4KbbcXltBaBajSzkL9YEaozszSbcOUaFDXkav8CeQ==", + "version": "9.2.6", + "resolved": "https://registry.npmjs.org/@luma.gl/gltf/-/gltf-9.2.6.tgz", + "integrity": "sha512-is3YkiGsWqWTmwldMz6PRaIUleufQfUKYjJTKpsF5RS1OnN+xdAO0mJq5qJTtOQpppWAU0VrmDFEVZ6R3qvm0A==", "license": "MIT", "dependencies": { "@loaders.gl/core": "^4.2.0", @@ -7850,9 +7867,9 @@ } }, "node_modules/@luma.gl/shadertools": { - "version": "9.2.5", - "resolved": "https://registry.npmjs.org/@luma.gl/shadertools/-/shadertools-9.2.5.tgz", - "integrity": "sha512-9upnT6r5exwotM1atc7Nwa7P69MKx+FavXWlabjk+nrRjeIJwzQ/3sXg9UfdDLavN/cDwGvnWz05UlbyABMmJg==", + "version": "9.2.6", + "resolved": "https://registry.npmjs.org/@luma.gl/shadertools/-/shadertools-9.2.6.tgz", + "integrity": "sha512-4+uUbynqPUra9d/z1nQChyHmhLgmKfSMjS7kOwLB6exSnhKnpHL3+Hu9fv55qyaX50nGH3oHawhGtJ6RRvu65w==", "license": "MIT", "dependencies": { "@math.gl/core": "^4.1.0", @@ -7864,12 +7881,12 @@ } }, "node_modules/@luma.gl/webgl": { - "version": "9.2.5", - "resolved": "https://registry.npmjs.org/@luma.gl/webgl/-/webgl-9.2.5.tgz", - "integrity": "sha512-FW5e+zxPuMI6gOJI6az5UnACrRwitzcghyUCVJBQq6/ZK/Z7bjBP5JQgd287DmFXrhLUrNBJ5NYRLmfbraGdDw==", + "version": "9.2.6", + "resolved": "https://registry.npmjs.org/@luma.gl/webgl/-/webgl-9.2.6.tgz", + "integrity": "sha512-NGBTdxJMk7j8Ygr1zuTyAvr1Tw+EpupMIQo7RelFjEsZXg6pujFqiDMM+rgxex8voCeuhWBJc7Rs+MoSqd46UQ==", "license": "MIT", "dependencies": { - "@luma.gl/constants": "9.2.5", + "@luma.gl/constants": "9.2.6", "@math.gl/types": "^4.1.0", "@probe.gl/env": "^4.0.8" }, @@ -9494,24 +9511,24 @@ "license": "MIT" }, "node_modules/@probe.gl/env": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@probe.gl/env/-/env-4.1.0.tgz", - "integrity": "sha512-5ac2Jm2K72VCs4eSMsM7ykVRrV47w32xOGMvcgqn8vQdEMF9PRXyBGYEV9YbqRKWNKpNKmQJVi4AHM/fkCxs9w==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@probe.gl/env/-/env-4.1.1.tgz", + "integrity": "sha512-+68seNDMVsEegRB47pFA/Ws1Fjy8agcFYXxzorKToyPcD6zd+gZ5uhwoLd7TzsSw6Ydns//2KEszWn+EnNHTbA==", "license": "MIT" }, "node_modules/@probe.gl/log": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@probe.gl/log/-/log-4.1.0.tgz", - "integrity": "sha512-r4gRReNY6f+OZEMgfWEXrAE2qJEt8rX0HsDJQXUBMoc+5H47bdB7f/5HBHAmapK8UydwPKL9wCDoS22rJ0yq7Q==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@probe.gl/log/-/log-4.1.1.tgz", + "integrity": "sha512-kcZs9BT44pL7hS1OkRGKYRXI/SN9KejUlPD+BY40DguRLzdC5tLG/28WGMyfKdn/51GT4a0p+0P8xvDn1Ez+Kg==", "license": "MIT", "dependencies": { - "@probe.gl/env": "4.1.0" + "@probe.gl/env": "4.1.1" } }, "node_modules/@probe.gl/stats": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@probe.gl/stats/-/stats-4.1.0.tgz", - "integrity": "sha512-EI413MkWKBDVNIfLdqbeNSJTs7ToBz/KVGkwi3D+dQrSIkRI2IYbWGAU3xX+D6+CI4ls8ehxMhNpUVMaZggDvQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@probe.gl/stats/-/stats-4.1.1.tgz", + "integrity": "sha512-4VpAyMHOqydSvPlEyHwXaE+AkIdR03nX+Qhlxsk2D/IW4OVmDZgIsvJB1cDzyEEtcfKcnaEbfXeiPgejBceT6g==", "license": "MIT" }, "node_modules/@puppeteer/browsers": { @@ -14008,434 +14025,2047 @@ "type": "github", "url": "https://github.com/sponsors/gregberge" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@testing-library/dom": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", + "integrity": "sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@testing-library/dom/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "12.1.5", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", + "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^8.0.0", + "@types/react-dom": "<18.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": "<18.0.0", + "react-dom": "<18.0.0" + } + }, + "node_modules/@testing-library/react-hooks": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz", + "integrity": "sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "react-error-boundary": "^3.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0", + "react": "^16.9.0 || ^17.0.0", + "react-dom": "^16.9.0 || ^17.0.0", + "react-test-renderer": "^16.9.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-test-renderer": { + "optional": true + } + } + }, + "node_modules/@testing-library/react-hooks/node_modules/react-error-boundary": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", + "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, + "node_modules/@testing-library/user-event": { + "version": "12.8.3", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.8.3.tgz", + "integrity": "sha512-IR0iWbFkgd56Bu5ZI/ej8yQwrkCv8Qydx6RzwbKz9faXazR/+5tvYKsZQgyXJiwgpcva127YO6JcWy7YlCfofQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "license": "MIT" + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", + "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@turf/along": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/along/-/along-7.3.4.tgz", + "integrity": "sha512-PvIoXin0I1t3nRwJz7uqR6fsxDMqdGwJq90qGOeqkNwlZqlF+5o2wKHPwYwi0RXZhLvxRP5qlbNIvV8ADdbWxw==", + "license": "MIT", + "dependencies": { + "@turf/bearing": "7.3.4", + "@turf/destination": "7.3.4", + "@turf/distance": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/along/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/along/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/area": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/area/-/area-7.3.4.tgz", + "integrity": "sha512-UEQQFw2XwHpozSBAMEtZI3jDsAad4NnHL/poF7/S6zeDCjEBCkt3MYd6DSGH/cvgcOozxH/ky3/rIVSMZdx4vA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/area/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/area/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bbox": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-7.3.4.tgz", + "integrity": "sha512-D5ErVWtfQbEPh11yzI69uxqrcJmbPU/9Y59f1uTapgwAwQHQztDWgsYpnL3ns8r1GmPWLP8sGJLVTIk2TZSiYA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bbox-polygon": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/bbox-polygon/-/bbox-polygon-7.3.4.tgz", + "integrity": "sha512-XCDYQwCA41Bum3R1xX0Na1nR4ozoe/pCYy5bxqrzyMs87kPJUIfBrD5IWxjnZyLqFpfEpolMHJz5ed1uA2PanQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bbox-polygon/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bbox/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bbox/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bearing": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-7.3.4.tgz", + "integrity": "sha512-zvFjapyFaOrM8nBtAND7f4yb0BJV0jyj6cyoXyTYqLY+3Hn0eHgL0M8lwxDLbTom5KfqYDHDVDQC3+VSfypoEA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bearing/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bearing/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-clockwise": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-5.1.5.tgz", + "integrity": "sha512-FqbmEEOJ4rU4/2t7FKx0HUWmjFEVqR+NJrFP7ymGSjja2SQ7Q91nnBihGuT+yuHHl6ElMjQ3ttsB/eTmyCycxA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^5.1.5", + "@turf/invariant": "^5.1.5" + } + }, + "node_modules/@turf/boolean-point-in-polygon": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-7.3.4.tgz", + "integrity": "sha512-v/4hfyY90Vz9cDgs2GwjQf+Lft8o7mNCLJOTz/iv8SHAIgMMX0czEoIaNVOJr7tBqPqwin1CGwsncrkf5C9n8Q==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@types/geojson": "^7946.0.10", + "point-in-polygon-hao": "^1.1.0", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-point-in-polygon/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-point-in-polygon/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-point-on-line": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-on-line/-/boolean-point-on-line-7.3.4.tgz", + "integrity": "sha512-70gm5x6YQOZKcw0b/O4jjMwVWnFj+Zb6TXozLgZFDZShc8pgTQtZku7K+HKZ7Eya+7usHIB4IimZauomOMa+iw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-point-on-line/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-point-on-line/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-within": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/boolean-within/-/boolean-within-7.3.4.tgz", + "integrity": "sha512-eLgi803gz0KcYkyxnnqnz9Vd6tw2/0eAExe/Rq8sO0dqypaSiomSumxjqu89d/yo24Qz8gW7c0kJ6YihNbMYxA==", + "license": "MIT", + "dependencies": { + "@turf/bbox": "7.3.4", + "@turf/boolean-point-in-polygon": "7.3.4", + "@turf/boolean-point-on-line": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@turf/line-split": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-within/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-within/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/buffer": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/buffer/-/buffer-7.3.4.tgz", + "integrity": "sha512-MVOCBDuOl3KGDsh2stW12RmiFaFeSkVjeUbZ+ADUtIVnv+jlFsmjBpFtsEw8s9YQn5g0667QppOshm0FBHA57Q==", + "license": "MIT", + "dependencies": { + "@turf/bbox": "7.3.4", + "@turf/center": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/jsts": "^2.7.1", + "@turf/meta": "7.3.4", + "@turf/projection": "7.3.4", + "@types/geojson": "^7946.0.10", + "d3-geo": "1.7.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/buffer/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/buffer/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/buffer/node_modules/d3-geo": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.7.1.tgz", + "integrity": "sha512-O4AempWAr+P5qbk2bC2FuN/sDW4z+dN2wDf9QV3bxQt4M5HfOEeXLgJ/UKQW0+o1Dj8BE+L5kiDbdWUMjsmQpw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1" + } + }, + "node_modules/@turf/center": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/center/-/center-7.3.4.tgz", + "integrity": "sha512-4SsLMDHWthXbyIHsczgFCo4fx+8tC8w2+B5HdEuY+P+cSOOL4T+6QQzd7WWjuN/Y3ndowFssUmwRrvXuwVRxQA==", + "license": "MIT", + "dependencies": { + "@turf/bbox": "7.3.4", + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/center/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/centroid": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-7.3.4.tgz", + "integrity": "sha512-6c3kyTSKBrmiPMe75UkHw6MgedroZ6eR5usEvdlDhXgA3MudFPXIZkMFmMd1h9XeJ9xFfkmq+HPCdF0cOzvztA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/centroid/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/centroid/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/circle": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/circle/-/circle-7.3.4.tgz", + "integrity": "sha512-6ccr5iT51/XONF+pbpkqoRxKX4ZVWLubXb1frGCnClv2suo1UIY9SIlINNctVDupXd2P9PpqZCbrXATrcrokPg==", + "license": "MIT", + "dependencies": { + "@turf/destination": "7.3.4", + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/circle/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/clone": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-5.1.5.tgz", + "integrity": "sha512-//pITsQ8xUdcQ9pVb4JqXiSqG4dos5Q9N4sYFoWghX21tfOV2dhc5TGqYOhnHrQS7RiKQL1vQ48kIK34gQ5oRg==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^5.1.5" + } + }, + "node_modules/@turf/destination": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/destination/-/destination-7.3.4.tgz", + "integrity": "sha512-YxoUJwkKmTHiRFQxMQOP0tz8Vy+ga5EXl+C+F/WubjDLwT1AJu5y8CNIjLvWyjPWckj/vZG4u/1js5bx6MLADA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/destination/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/destination/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/difference": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/difference/-/difference-7.3.4.tgz", + "integrity": "sha512-kIxizNQrYLO2rtqUIeed0tPycicrXoipy/g9d4mjv91kzBEbwpyojz9zi8U9G1ISBfCEgA7wsViQD0r+8qzxXw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "polyclip-ts": "^0.16.8", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/difference/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/difference/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/distance": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/distance/-/distance-7.3.4.tgz", + "integrity": "sha512-9drWgd46uHPPyzgrcRQLgSvdS/SjVlQ6ZIBoRQagS5P2kSjUbcOXHIMeOSPwfxwlKhEtobLyr+IiR2ns1TfF8w==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/distance/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/distance/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/ellipse": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/ellipse/-/ellipse-7.3.4.tgz", + "integrity": "sha512-SMgbERZl12j7H8YaIofmnf0NwAvdF5Wly4tjI/eUhj/sFOKrKXOS1lvCSBJ6uSV9tFijl3ecGOVOlTpURdZ30g==", + "license": "MIT", + "dependencies": { + "@turf/destination": "7.3.4", + "@turf/distance": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@turf/transform-rotate": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/ellipse/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/ellipse/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/geojson-rbush": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/geojson-rbush/-/geojson-rbush-7.3.4.tgz", + "integrity": "sha512-aDG/5mMCgKduqBwZ3XpLOdlE2hizV3fM+5dHCWyrBepCQLeM/QRvvpBDCdQKDWKpoIBmrGGYDNiOofnf3QmGhg==", + "license": "MIT", + "dependencies": { + "@turf/bbox": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "rbush": "^3.0.1", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/geojson-rbush/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/geojson-rbush/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/helpers": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-5.1.5.tgz", + "integrity": "sha512-/lF+JR+qNDHZ8bF9d+Cp58nxtZWJ3sqFe6n3u3Vpj+/0cqkjk4nXKYBSY0azm+GIYB5mWKxUXvuP/m0ZnKj1bw==", + "license": "MIT" + }, + "node_modules/@turf/intersect": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/intersect/-/intersect-7.3.4.tgz", + "integrity": "sha512-VsqMEMeRWWs2mjwI7sTlUgH1cEfugTGhQ0nF8ncHG7YKd9HUUTzIKpn9FJeoguPWIYITcy1ar4yJEOU/hteBVw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "polyclip-ts": "^0.16.8", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/intersect/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/intersect/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/invariant": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-5.2.0.tgz", + "integrity": "sha512-28RCBGvCYsajVkw2EydpzLdcYyhSA77LovuOvgCJplJWaNVyJYH6BOR3HR9w50MEkPqb/Vc/jdo6I6ermlRtQA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^5.1.5" + } + }, + "node_modules/@turf/jsts": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@turf/jsts/-/jsts-2.7.2.tgz", + "integrity": "sha512-zAezGlwWHPyU0zxwcX2wQY3RkRpwuoBmhhNE9HY9kWhFDkCxZ3aWK5URKwa/SWKJbj9aztO+8vtdiBA28KVJFg==", + "license": "(EDL-1.0 OR EPL-1.0)", + "dependencies": { + "jsts": "2.7.1" + } + }, + "node_modules/@turf/kinks": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/kinks/-/kinks-7.3.4.tgz", + "integrity": "sha512-LZTKELWxvXl0vc9ZxVgi0v07fO9+2FrZOam2B10fz/eGjy3oKNazU5gjggbnc499wEIcJS4hN+VyjQZrmsJAdQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/kinks/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-intersect": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/line-intersect/-/line-intersect-7.3.4.tgz", + "integrity": "sha512-XygbTvHa6A+v6l2ZKYtS8AAWxwmrPxKxfBbdH75uED1JvdytSLWYTKGlcU3soxd9sYb4x/g9sDvRIVyU6Lucrg==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "sweepline-intersections": "^1.5.0", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-intersect/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-segment": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/line-segment/-/line-segment-7.3.4.tgz", + "integrity": "sha512-UeISzf/JHoWEY5yeoyvKwA5epWcvJMCpCwbIMolvfTC5pp+IVozjHPVCRvRWuzmbmAvetcW0unL5bjqi0ADmuQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-segment/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-segment/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-segment/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-split": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/line-split/-/line-split-7.3.4.tgz", + "integrity": "sha512-l1zmCSUnGsiN4gf22Aw91a2VnYs5DZS67FdkYqKgr+wPEAL/gpQgIBBWSTmhwY8zb3NEqty+f/gMEe8EJAWYng==", + "license": "MIT", + "dependencies": { + "@turf/bbox": "7.3.4", + "@turf/geojson-rbush": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@turf/line-intersect": "7.3.4", + "@turf/line-segment": "7.3.4", + "@turf/meta": "7.3.4", + "@turf/nearest-point-on-line": "7.3.4", + "@turf/truncate": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-split/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-split/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-split/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/meta": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-5.2.0.tgz", + "integrity": "sha512-ZjQ3Ii62X9FjnK4hhdsbT+64AYRpaI8XMBMcyftEOGSmPMUVnkbvuv3C9geuElAXfQU7Zk1oWGOcrGOD9zr78Q==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^5.1.5" + } + }, + "node_modules/@turf/midpoint": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/midpoint/-/midpoint-7.3.4.tgz", + "integrity": "sha512-/XAeGvsz8l5HaqcP7TUlexzGfibqXozQgBZ8rH7az6op2Dfm3pL/Z7bKLHoVavM0ccBg0Pt7g6j9NM54kZWdKA==", + "license": "MIT", + "dependencies": { + "@turf/bearing": "7.3.4", + "@turf/destination": "7.3.4", + "@turf/distance": "7.3.4", + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/midpoint/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/nearest-point-on-line": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/nearest-point-on-line/-/nearest-point-on-line-7.3.4.tgz", + "integrity": "sha512-DQrP3lRju83rIXFN68tUEpc7ki/eRwdwBkK2CTT4RAcyCxbcH2NGJPQv8dYiww/Ar77u1WLVn+aINXZH904dWw==", + "license": "MIT", + "dependencies": { + "@turf/distance": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/nearest-point-on-line/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/nearest-point-on-line/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/nearest-point-on-line/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/point-to-line-distance": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/point-to-line-distance/-/point-to-line-distance-7.3.4.tgz", + "integrity": "sha512-IdPAxlAQZj7FCZg+ObyVHlNdqwLL/oxYoQjpxMNJ511gNxokCtEv0aeRZQjYOYIxr9Ss97v3yo3ILJaF9V2kPw==", + "license": "MIT", + "dependencies": { + "@turf/bearing": "7.3.4", + "@turf/distance": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@turf/meta": "7.3.4", + "@turf/nearest-point-on-line": "7.3.4", + "@turf/projection": "7.3.4", + "@turf/rhumb-bearing": "7.3.4", + "@turf/rhumb-distance": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/point-to-line-distance/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/point-to-line-distance/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/point-to-line-distance/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/polygon-to-line": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/polygon-to-line/-/polygon-to-line-7.3.4.tgz", + "integrity": "sha512-xhmOZ5rHZAKLUDLeYKWMsX84ip8CCGOcGLBHtPPYOjdIDHddMV6Sxt5kVgkmlZpK6NEWEmOD6lYR4obxHcHlGA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/polygon-to-line/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/polygon-to-line/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/projection": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/projection/-/projection-7.3.4.tgz", + "integrity": "sha512-p91zOaLmzoBHzU/2H6Ot1tOhTmAom85n1P7I4Oo0V9xU8hmJXWfNnomLFf/6rnkKDIFZkncLQIBz4iIecZ61sA==", + "license": "MIT", + "dependencies": { + "@turf/clone": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/projection/node_modules/@turf/clone": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-7.3.4.tgz", + "integrity": "sha512-pwQ+RyQw986uu7IulY/18NRAebwZZScb084bvVqVkTrllwLSv4oVBqUxmUMiwtp+PNdiRGRFOvNyZqtRsiD+Jw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/projection/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/projection/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rewind": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-5.1.5.tgz", + "integrity": "sha512-Gdem7JXNu+G4hMllQHXRFRihJl3+pNl7qY+l4qhQFxq+hiU1cQoVFnyoleIqWKIrdK/i2YubaSwc3SCM7N5mMw==", + "license": "MIT", + "dependencies": { + "@turf/boolean-clockwise": "^5.1.5", + "@turf/clone": "^5.1.5", + "@turf/helpers": "^5.1.5", + "@turf/invariant": "^5.1.5", + "@turf/meta": "^5.1.5" + } + }, + "node_modules/@turf/rhumb-bearing": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-7.3.4.tgz", + "integrity": "sha512-tvX1toSo80q0iL0cUMMXpSKsCCfOjRqDGCmOdR6B9shhk6xP1ZM2PLQDr+MFPBFeGyQuyY4CNFkV2+3DF49vYw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rhumb-bearing/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rhumb-bearing/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rhumb-destination": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/rhumb-destination/-/rhumb-destination-7.3.4.tgz", + "integrity": "sha512-6HikEb5nm2A18FQWk6vVLMQkc099I/7c69j47RYM27xQK8J8uBCNk1zLYyMPcZTh24xcNSbZ1iPHDsDOqw6wWQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rhumb-destination/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rhumb-destination/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rhumb-distance": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-7.3.4.tgz", + "integrity": "sha512-phwskeijdgYMsR3qDQmytfsg2iZcp3uWK7UFc76wKTEpxozbDGFI4enX5gXvZPpyI1iD7gsktGqHsO33AjnFDA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rhumb-distance/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@svgr/babel-preset": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", - "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", - "dev": true, + "node_modules/@turf/rhumb-distance/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", "license": "MIT", "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", - "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", - "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", - "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", - "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", - "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", - "@svgr/babel-plugin-transform-svg-component": "8.0.0" - }, - "engines": { - "node": ">=14" + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "url": "https://opencollective.com/turf" } }, - "node_modules/@svgr/core": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", - "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", - "dev": true, + "node_modules/@turf/transform-rotate": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/transform-rotate/-/transform-rotate-7.3.4.tgz", + "integrity": "sha512-pbUG6QLwyJvvitq4aAq4IQH79X8T0NmEPUGDUEEP69yW7t4+UZjDBAVbCKwpOc8gtsK0K5yvxlZ0e2CdtpNmEw==", "license": "MIT", "dependencies": { - "@babel/core": "^7.21.3", - "@svgr/babel-preset": "8.1.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^8.1.3", - "snake-case": "^3.0.4" - }, - "engines": { - "node": ">=14" + "@turf/centroid": "7.3.4", + "@turf/clone": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@turf/meta": "7.3.4", + "@turf/rhumb-bearing": "7.3.4", + "@turf/rhumb-destination": "7.3.4", + "@turf/rhumb-distance": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "url": "https://opencollective.com/turf" } }, - "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", - "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", - "dev": true, + "node_modules/@turf/transform-rotate/node_modules/@turf/clone": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-7.3.4.tgz", + "integrity": "sha512-pwQ+RyQw986uu7IulY/18NRAebwZZScb084bvVqVkTrllwLSv4oVBqUxmUMiwtp+PNdiRGRFOvNyZqtRsiD+Jw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.21.3", - "entities": "^4.4.0" - }, - "engines": { - "node": ">=14" + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "url": "https://opencollective.com/turf" } }, - "node_modules/@svgr/plugin-jsx": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", - "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", - "dev": true, + "node_modules/@turf/transform-rotate/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", "license": "MIT", "dependencies": { - "@babel/core": "^7.21.3", - "@svgr/babel-preset": "8.1.0", - "@svgr/hast-util-to-babel-ast": "8.0.0", - "svg-parser": "^2.0.4" - }, - "engines": { - "node": ">=14" + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@svgr/core": "*" + "url": "https://opencollective.com/turf" } }, - "node_modules/@svgr/plugin-svgo": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", - "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", - "dev": true, + "node_modules/@turf/transform-rotate/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", "license": "MIT", "dependencies": { - "cosmiconfig": "^8.1.3", - "deepmerge": "^4.3.1", - "svgo": "^3.0.2" - }, - "engines": { - "node": ">=14" + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@svgr/core": "*" + "url": "https://opencollective.com/turf" } }, - "node_modules/@svgr/webpack": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", - "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", - "dev": true, + "node_modules/@turf/transform-rotate/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", "license": "MIT", "dependencies": { - "@babel/core": "^7.21.3", - "@babel/plugin-transform-react-constant-elements": "^7.21.3", - "@babel/preset-env": "^7.20.2", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.21.0", - "@svgr/core": "8.1.0", - "@svgr/plugin-jsx": "8.1.0", - "@svgr/plugin-svgo": "8.1.0" - }, - "engines": { - "node": ">=14" + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "url": "https://opencollective.com/turf" } }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, + "node_modules/@turf/transform-scale": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/transform-scale/-/transform-scale-7.3.4.tgz", + "integrity": "sha512-7gUIFFHaU3Ewj3rCzIu5Yo7Zjfv4R2ypjh6UWiMJnDavb7RQ8fn0AKKcNMA/vF/yxuncp2l3zoa2gygv4AKM8A==", "license": "MIT", "dependencies": { - "defer-to-connect": "^2.0.0" + "@turf/bbox": "7.3.4", + "@turf/center": "7.3.4", + "@turf/centroid": "7.3.4", + "@turf/clone": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@turf/meta": "7.3.4", + "@turf/rhumb-bearing": "7.3.4", + "@turf/rhumb-destination": "7.3.4", + "@turf/rhumb-distance": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@testing-library/dom": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", - "integrity": "sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==", + "node_modules/@turf/transform-scale/node_modules/@turf/clone": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-7.3.4.tgz", + "integrity": "sha512-pwQ+RyQw986uu7IulY/18NRAebwZZScb084bvVqVkTrllwLSv4oVBqUxmUMiwtp+PNdiRGRFOvNyZqtRsiD+Jw==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, - "engines": { - "node": ">=12" + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@testing-library/dom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@turf/transform-scale/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://opencollective.com/turf" } }, - "node_modules/@testing-library/jest-dom": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", - "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "node_modules/@turf/transform-scale/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", "license": "MIT", "dependencies": { - "@adobe/css-tools": "^4.4.0", - "aria-query": "^5.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "picocolors": "^1.1.1", - "redent": "^3.0.0" + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", - "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", - "license": "MIT" - }, - "node_modules/@testing-library/react": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", - "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", + "node_modules/@turf/transform-scale/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.0.0", - "@types/react-dom": "<18.0.0" - }, - "engines": { - "node": ">=12" + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, - "peerDependencies": { - "react": "<18.0.0", - "react-dom": "<18.0.0" + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@testing-library/react-hooks": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz", - "integrity": "sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==", + "node_modules/@turf/transform-translate": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/transform-translate/-/transform-translate-7.3.4.tgz", + "integrity": "sha512-qbSIEueOR8mNB7p4EB88vHvUAyuSBM8zxP68UiiTNV3Gh+OZF2VXTFiu3EFYMTaD9sE6Lxmzvv3fjW8N2q82pw==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5", - "react-error-boundary": "^3.1.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "@types/react": "^16.9.0 || ^17.0.0", - "react": "^16.9.0 || ^17.0.0", - "react-dom": "^16.9.0 || ^17.0.0", - "react-test-renderer": "^16.9.0 || ^17.0.0" + "@turf/clone": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@turf/meta": "7.3.4", + "@turf/rhumb-destination": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-test-renderer": { - "optional": true - } + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@testing-library/react-hooks/node_modules/react-error-boundary": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", - "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "node_modules/@turf/transform-translate/node_modules/@turf/clone": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-7.3.4.tgz", + "integrity": "sha512-pwQ+RyQw986uu7IulY/18NRAebwZZScb084bvVqVkTrllwLSv4oVBqUxmUMiwtp+PNdiRGRFOvNyZqtRsiD+Jw==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=10", - "npm": ">=6" + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, - "peerDependencies": { - "react": ">=16.13.1" + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@testing-library/user-event": { - "version": "12.8.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.8.3.tgz", - "integrity": "sha512-IR0iWbFkgd56Bu5ZI/ej8yQwrkCv8Qydx6RzwbKz9faXazR/+5tvYKsZQgyXJiwgpcva127YO6JcWy7YlCfofQ==", + "node_modules/@turf/transform-translate/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=10", - "npm": ">=6" + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, + "node_modules/@turf/transform-translate/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tootallnate/quickjs-emscripten": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", - "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10.13.0" + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "license": "MIT" - }, - "node_modules/@tufjs/canonical-json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", - "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", - "dev": true, + "node_modules/@turf/transform-translate/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", "license": "MIT", - "engines": { - "node": "^16.14.0 || >=18.0.0" + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@tufjs/models": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", - "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", - "dev": true, + "node_modules/@turf/truncate": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/truncate/-/truncate-7.3.4.tgz", + "integrity": "sha512-VPXdae9+RLLM19FMrJgt7QANBikm7DxPbfp/dXgzE4Ca7v+mJ4T1fYc7gCZDaqOrWMccHKbvv4iSuW7YZWdIIA==", "license": "MIT", "dependencies": { - "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.4" + "@turf/helpers": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" }, - "engines": { - "node": "^16.14.0 || >=18.0.0" + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/boolean-clockwise": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-5.1.5.tgz", - "integrity": "sha512-FqbmEEOJ4rU4/2t7FKx0HUWmjFEVqR+NJrFP7ymGSjja2SQ7Q91nnBihGuT+yuHHl6ElMjQ3ttsB/eTmyCycxA==", + "node_modules/@turf/truncate/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", "license": "MIT", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/clone": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-5.1.5.tgz", - "integrity": "sha512-//pITsQ8xUdcQ9pVb4JqXiSqG4dos5Q9N4sYFoWghX21tfOV2dhc5TGqYOhnHrQS7RiKQL1vQ48kIK34gQ5oRg==", + "node_modules/@turf/truncate/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", "license": "MIT", "dependencies": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/helpers": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-5.1.5.tgz", - "integrity": "sha512-/lF+JR+qNDHZ8bF9d+Cp58nxtZWJ3sqFe6n3u3Vpj+/0cqkjk4nXKYBSY0azm+GIYB5mWKxUXvuP/m0ZnKj1bw==", - "license": "MIT" - }, - "node_modules/@turf/invariant": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-5.2.0.tgz", - "integrity": "sha512-28RCBGvCYsajVkw2EydpzLdcYyhSA77LovuOvgCJplJWaNVyJYH6BOR3HR9w50MEkPqb/Vc/jdo6I6ermlRtQA==", + "node_modules/@turf/union": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/union/-/union-7.3.4.tgz", + "integrity": "sha512-JJYyPMmGcrTa9sPv2ief2QU9Hb//cEAU1zgKu/OfoCMa9a8Imp5QVm9UTAkhGlc+4qm/N/X16iJ+cvVWaxPjkg==", "license": "MIT", "dependencies": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "polyclip-ts": "^0.16.8", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/meta": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-5.2.0.tgz", - "integrity": "sha512-ZjQ3Ii62X9FjnK4hhdsbT+64AYRpaI8XMBMcyftEOGSmPMUVnkbvuv3C9geuElAXfQU7Zk1oWGOcrGOD9zr78Q==", + "node_modules/@turf/union/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", "license": "MIT", "dependencies": { - "@turf/helpers": "^5.1.5" + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/rewind": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-5.1.5.tgz", - "integrity": "sha512-Gdem7JXNu+G4hMllQHXRFRihJl3+pNl7qY+l4qhQFxq+hiU1cQoVFnyoleIqWKIrdK/i2YubaSwc3SCM7N5mMw==", + "node_modules/@turf/union/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", "license": "MIT", "dependencies": { - "@turf/boolean-clockwise": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@tybys/wasm-util": { @@ -26383,9 +28013,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "devOptional": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/events": { "version": "3.3.0", @@ -35459,6 +37087,15 @@ "jss": "10.10.0" } }, + "node_modules/jsts": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/jsts/-/jsts-2.7.1.tgz", + "integrity": "sha512-x2wSZHEBK20CY+Wy+BPE7MrFQHW6sIsdaGUMEqmGAio+3gFzQaBYPwLRonUfQf9Ak8pBieqj9tUofX1+WtAEIg==", + "license": "(EDL-1.0 OR EPL-1.0)", + "engines": { + "node": ">= 12" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -36679,6 +38316,13 @@ "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", "license": "MIT" }, + "node_modules/lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==", + "deprecated": "This package is deprecated. Use destructuring assignment syntax instead.", + "license": "MIT" + }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -36699,6 +38343,12 @@ "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", "license": "MIT" }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT" + }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -44324,6 +45974,15 @@ "node": ">= 0.8.0" } }, + "node_modules/point-in-polygon-hao": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/point-in-polygon-hao/-/point-in-polygon-hao-1.2.4.tgz", + "integrity": "sha512-x2pcvXeqhRHlNRdhLs/tgFapAbSSe86wa/eqmj1G6pWftbEs5aVRJhRGM6FYSUERKu0PjekJzMq0gsI2XyiclQ==", + "license": "MIT", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/polished": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", @@ -44336,6 +45995,16 @@ "node": ">=10" } }, + "node_modules/polyclip-ts": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/polyclip-ts/-/polyclip-ts-0.16.8.tgz", + "integrity": "sha512-JPtKbDRuPEuAjuTdhR62Gph7Is2BS1Szx69CFOO3g71lpJDFo78k4tFyi+qFOMVPePEzdSKkpGU3NBXPHHjvKQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.1.0", + "splaytree-ts": "^1.0.2" + } + }, "node_modules/popper.js": { "version": "1.16.1-lts", "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", @@ -51546,6 +53215,12 @@ "integrity": "sha512-D50hKrjZgBzqD3FT2Ek53f2dcDLAQT8SSGrzj3vidNH5ISRgceeGVJ2dQIthKOuayqFXfFjXheHNo4bbt9LhRQ==", "license": "MIT" }, + "node_modules/splaytree-ts": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/splaytree-ts/-/splaytree-ts-1.0.2.tgz", + "integrity": "sha512-0kGecIZNIReCSiznK3uheYB8sbstLjCZLiwcQwbmLhgHJj2gz6OnSPkVzJQCMnmEz1BQ4gPK59ylhBoEWOhGNA==", + "license": "BDS-3-Clause" + }, "node_modules/split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", @@ -52550,6 +54225,21 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/sweepline-intersections": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sweepline-intersections/-/sweepline-intersections-1.5.0.tgz", + "integrity": "sha512-AoVmx72QHpKtItPu72TzFL+kcYjd67BPLDoR0LarIk+xyaRg+pDTMFXndIEvZf9xEKnJv6JdhgRMnocoG0D3AQ==", + "license": "MIT", + "dependencies": { + "tinyqueue": "^2.0.0" + } + }, + "node_modules/sweepline-intersections/node_modules/tinyqueue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", + "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==", + "license": "ISC" + }, "node_modules/symbol-observable": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", @@ -58475,6 +60165,7 @@ "license": "Apache-2.0", "dependencies": { "@ant-design/icons": "^5.6.1", + "@deck.gl-community/editable-layers": "^9.2.8", "@deck.gl/aggregation-layers": "^9.1.14", "@deck.gl/core": "^9.1.14", "@deck.gl/extensions": "^9.1.14", @@ -58521,6 +60212,206 @@ "react-map-gl": "^6.1.19" } }, + "plugins/geoset-map-chart/node_modules/@deck.gl-community/editable-layers": { + "version": "9.2.8", + "resolved": "https://registry.npmjs.org/@deck.gl-community/editable-layers/-/editable-layers-9.2.8.tgz", + "integrity": "sha512-E9i4LwstJ+d/BqF46afhKVNHZuQt4gwdWL6jqsD4lfzr0IdWJMGmg+r8xtwHYK+nhbraHfX+ddDNUR03bPvswg==", + "license": "MIT", + "dependencies": { + "@math.gl/web-mercator": ">=4.0.1", + "@turf/along": "^7.2.0", + "@turf/area": "^7.2.0", + "@turf/bbox": "^7.2.0", + "@turf/bbox-polygon": "^7.2.0", + "@turf/bearing": "^7.2.0", + "@turf/boolean-point-in-polygon": "^7.2.0", + "@turf/boolean-within": "^7.2.0", + "@turf/buffer": "^7.2.0", + "@turf/center": "^7.2.0", + "@turf/centroid": "^7.2.0", + "@turf/circle": "^7.2.0", + "@turf/clone": "^7.2.0", + "@turf/destination": "^7.2.0", + "@turf/difference": "^7.2.0", + "@turf/distance": "^7.2.0", + "@turf/ellipse": "^7.2.0", + "@turf/helpers": "^7.2.0", + "@turf/intersect": "^7.2.0", + "@turf/invariant": "^7.2.0", + "@turf/kinks": "^7.2.0", + "@turf/line-intersect": "^7.2.0", + "@turf/meta": "^7.2.0", + "@turf/midpoint": "^7.2.0", + "@turf/nearest-point-on-line": "^7.2.0", + "@turf/point-to-line-distance": "^7.2.0", + "@turf/polygon-to-line": "^7.2.0", + "@turf/rewind": "^7.2.0", + "@turf/rhumb-bearing": "^7.2.0", + "@turf/rhumb-destination": "^7.2.0", + "@turf/rhumb-distance": "^7.2.0", + "@turf/transform-rotate": "^7.2.0", + "@turf/transform-scale": "^7.2.0", + "@turf/transform-translate": "^7.2.0", + "@turf/union": "^7.2.0", + "@types/geojson": "^7946.0.16", + "eventemitter3": "^5.0.0", + "lodash.omit": "^4.1.1", + "lodash.throttle": "^4.1.1", + "preact": "^10.17.0", + "uuid": "9.0.0" + }, + "peerDependencies": { + "@deck.gl-community/layers": "^9.2.0-beta", + "@deck.gl/core": "~9.2.8", + "@deck.gl/extensions": "~9.2.8", + "@deck.gl/geo-layers": "~9.2.8", + "@deck.gl/layers": "~9.2.8", + "@deck.gl/mesh-layers": "~9.2.8", + "@luma.gl/constants": "~9.2.6", + "@luma.gl/core": "~9.2.6", + "@luma.gl/engine": "~9.2.6", + "@math.gl/core": ">=4.0.1" + } + }, + "plugins/geoset-map-chart/node_modules/@deck.gl/extensions": { + "version": "9.2.11", + "resolved": "https://registry.npmjs.org/@deck.gl/extensions/-/extensions-9.2.11.tgz", + "integrity": "sha512-zlpM4Bg1ifBziW1Juiii9NY5gyW2rEhyVTWnhagH/bpTCZ2E73OhnToYt1ouqmoxL6lMtIjhRXz6LPb7tJbHHQ==", + "license": "MIT", + "dependencies": { + "@luma.gl/constants": "~9.2.6", + "@luma.gl/shadertools": "~9.2.6", + "@math.gl/core": "^4.1.0" + }, + "peerDependencies": { + "@deck.gl/core": "~9.2.0", + "@luma.gl/core": "~9.2.6", + "@luma.gl/engine": "~9.2.6" + } + }, + "plugins/geoset-map-chart/node_modules/@deck.gl/geo-layers": { + "version": "9.2.11", + "resolved": "https://registry.npmjs.org/@deck.gl/geo-layers/-/geo-layers-9.2.11.tgz", + "integrity": "sha512-Mr3yvKyZMPmQ3ho0hSqcJu1p7a881RqQaq/dRaPs2VP56UAkfk1e10zxXnrZ9/Dmo2MR5PH0j8tkOoGR3zKbfA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@loaders.gl/3d-tiles": "~4.3.4", + "@loaders.gl/gis": "~4.3.4", + "@loaders.gl/loader-utils": "~4.3.4", + "@loaders.gl/mvt": "~4.3.4", + "@loaders.gl/schema": "~4.3.4", + "@loaders.gl/terrain": "~4.3.4", + "@loaders.gl/tiles": "~4.3.4", + "@loaders.gl/wms": "~4.3.4", + "@luma.gl/gltf": "~9.2.6", + "@luma.gl/shadertools": "~9.2.6", + "@math.gl/core": "^4.1.0", + "@math.gl/culling": "^4.1.0", + "@math.gl/web-mercator": "^4.1.0", + "@types/geojson": "^7946.0.8", + "a5-js": "^0.5.0", + "h3-js": "^4.1.0", + "long": "^3.2.0" + }, + "peerDependencies": { + "@deck.gl/core": "~9.2.0", + "@deck.gl/extensions": "~9.2.0", + "@deck.gl/layers": "~9.2.0", + "@deck.gl/mesh-layers": "~9.2.0", + "@loaders.gl/core": "~4.3.4", + "@luma.gl/core": "~9.2.6", + "@luma.gl/engine": "~9.2.6" + } + }, + "plugins/geoset-map-chart/node_modules/@turf/boolean-clockwise": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-7.3.4.tgz", + "integrity": "sha512-X/O+u/OsoJ99mujhlqviuB7HX0tdJ5931TBjNSseps43XtROVuB5PwBDgwKfu5lY1B4DSGAxbbxJ795RmPnguQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "plugins/geoset-map-chart/node_modules/@turf/clone": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-7.3.4.tgz", + "integrity": "sha512-pwQ+RyQw986uu7IulY/18NRAebwZZScb084bvVqVkTrllwLSv4oVBqUxmUMiwtp+PNdiRGRFOvNyZqtRsiD+Jw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "plugins/geoset-map-chart/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "plugins/geoset-map-chart/node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "plugins/geoset-map-chart/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "plugins/geoset-map-chart/node_modules/@turf/rewind": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-7.3.4.tgz", + "integrity": "sha512-4BZ8MHMujl4NAT7XnIs7JoOuDhpR96oDTB0RtqTeIP4onioIedVnw1ZA3Uq08sILGpR0qKLuDsvdz4x9jtbptg==", + "license": "MIT", + "dependencies": { + "@turf/boolean-clockwise": "7.3.4", + "@turf/clone": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, "plugins/geoset-map-chart/node_modules/d3-color": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", @@ -58591,6 +60482,15 @@ "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", "license": "ISC" }, + "plugins/geoset-map-chart/node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "plugins/legacy-plugin-chart-calendar": { "name": "@superset-ui/legacy-plugin-chart-calendar", "version": "0.20.3", diff --git a/superset-frontend/plugins/geoset-map-chart/package.json b/superset-frontend/plugins/geoset-map-chart/package.json index c690c51813..f50269e33f 100644 --- a/superset-frontend/plugins/geoset-map-chart/package.json +++ b/superset-frontend/plugins/geoset-map-chart/package.json @@ -25,6 +25,7 @@ ], "dependencies": { "@ant-design/icons": "^5.6.1", + "@deck.gl-community/editable-layers": "^9.2.8", "@deck.gl/aggregation-layers": "^9.1.14", "@deck.gl/core": "^9.1.14", "@deck.gl/extensions": "^9.1.14", diff --git a/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx b/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx index a34eee8388..25978b8be4 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx @@ -44,6 +44,11 @@ import { } from './utils/fitViewport'; import { LayerState } from './types'; import { MeasureState, useMeasureLayers } from './components/MeasureOverlay'; +import { + LASSO_CURSOR, + useLassoLayer, + LassoDrawMode, +} from './components/LassoOverlay'; import { Coordinate } from './utils/measureDistance'; const TICK = 250; // milliseconds @@ -65,6 +70,9 @@ export type DeckGLContainerProps = { onMeasureDragStart?: (coordinate: Coordinate) => void; onMeasureDrag?: (coordinate: Coordinate) => void; onMeasureDragEnd?: (coordinate: Coordinate) => void; + lassoIsActive?: boolean; + lassoDrawMode?: LassoDrawMode; + onLassoComplete?: (polygon: Coordinate[]) => void; onEmptyClick?: () => void; }; @@ -369,16 +377,26 @@ export const DeckGLContainer = memo( distance, } = useMeasureLayers(measureState, project); + // Get lasso editable layer (library-based drawing) + const lassoIsActive = props.lassoIsActive ?? false; + const lassoDrawMode = props.lassoDrawMode ?? 'freehand'; + const handleLassoComplete = props.onLassoComplete ?? (() => {}); + const { layers: lassoLayers } = useLassoLayer( + lassoIsActive, + handleLassoComplete, + lassoDrawMode, + ); + const allLayers = useMemo(() => { if (!layerStates || layerStates.length === 0) { - return measureLayers as Layer[]; + return [...measureLayers, ...lassoLayers] as Layer[]; } const layers = layerStates .map(ls => ls?.layer) .filter(Boolean) as Layer[]; - return [...layers, ...measureLayers] as Layer[]; - }, [layerStates, measureLayers]); + return [...layers, ...measureLayers, ...lassoLayers] as Layer[]; + }, [layerStates, measureLayers, lassoLayers]); useEffect(() => { if (!props.layerStates) return; @@ -551,6 +569,8 @@ export const DeckGLContainer = memo( (info: any) => { // Don't handle click if a drag was in progress (threshold was exceeded) if (measureDragRef.current) return; + // Suppress normal clicks during lasso mode + if (lassoIsActive) return; if (measureState.isActive && onMeasureClick && info.coordinate) { onMeasureClick(info.coordinate as Coordinate); } @@ -559,13 +579,18 @@ export const DeckGLContainer = memo( onEmptyClick(); } }, - [measureState.isActive, onMeasureClick, onEmptyClick], + [measureState.isActive, lassoIsActive, onMeasureClick, onEmptyClick], ); - // Cursor style for measure mode - use custom ruler cursor + // Cursor style for measure/lasso modes const getCursor = useCallback( - () => (measureState.isActive ? RULER_CURSOR : 'grab'), - [measureState.isActive], + () => + lassoIsActive + ? LASSO_CURSOR + : measureState.isActive + ? RULER_CURSOR + : 'grab', + [measureState.isActive, lassoIsActive], ); // Handle mouse down for drag-to-measure @@ -573,7 +598,6 @@ export const DeckGLContainer = memo( (e: React.MouseEvent) => { if (!measureState.isActive) return; - // Store initial position - don't start drag yet const rect = e.currentTarget.getBoundingClientRect(); mouseDownPosRef.current = { x: e.clientX - rect.left, @@ -596,14 +620,10 @@ export const DeckGLContainer = memo( const x = e.clientX - rect.left; const y = e.clientY - rect.top; - // Check if we've exceeded drag threshold if (!measureDragRef.current) { const dx = x - mouseDownPosRef.current.x; const dy = y - mouseDownPosRef.current.y; - const distance = Math.sqrt(dx * dx + dy * dy); - - if (distance >= DRAG_THRESHOLD) { - // Start drag from the initial mouse down position + if (Math.sqrt(dx * dx + dy * dy) >= DRAG_THRESHOLD) { measureDragRef.current = true; const startLngLat = map.unproject([ mouseDownPosRef.current.x, @@ -611,11 +631,10 @@ export const DeckGLContainer = memo( ]); props.onMeasureDragStart?.([startLngLat.lng, startLngLat.lat]); } else { - return; // Haven't moved enough yet + return; } } - // Continue drag const lngLat = map.unproject([x, y]); props.onMeasureDrag?.([lngLat.lng, lngLat.lat]); }, @@ -627,7 +646,6 @@ export const DeckGLContainer = memo( (e: React.MouseEvent) => { if (!measureState.isActive) return; - // Only finalize drag if we actually started dragging if (measureDragRef.current) { const map = mapRef.current?.getMap(); if (map) { @@ -639,17 +657,18 @@ export const DeckGLContainer = memo( } } - // Reset refs measureDragRef.current = false; mouseDownPosRef.current = null; }, [measureState.isActive, props.onMeasureDragEnd], ); - // Disable map panning when in measure mode - const controllerOptions = measureState.isActive - ? { dragPan: false, dragRotate: false } - : true; + // Disable map panning when in measure or lasso mode + // Lasso needs dragPan off so EditableGeoJsonLayer receives drag events + const controllerOptions = + measureState.isActive || lassoIsActive + ? { dragPan: false, dragRotate: false } + : true; // Calculate scale info using map projection (matches mapbox-gl ScaleControl exactly) // eslint-disable-next-line react-hooks/exhaustive-deps -- deps trigger recalc when map state changes diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx index 4525dc90ea..5008cc8262 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx @@ -48,6 +48,7 @@ import MultiLegend from '../components/MultiLegend'; import type { CategoryEntry, LegendEntry } from '../types'; import { useGroupedLegend } from '../utils/hooks'; import MapControls from '../components/MapControls'; +import type { Coordinate } from '../utils/measureDistance'; import { CategoryState, MetricLegend, RGBAColor } from '../utils/colors'; import { getGeometryType } from '../utils/dataProcessing'; import { fetchMapboxApiKey, getCachedMapboxApiKey } from '../utils/mapboxApi'; @@ -1012,18 +1013,44 @@ const DeckMulti = (props: DeckMultiProps) => { // Lasso selection state const [lassoIsActive, setLassoIsActive] = useState(false); - const [activeLassoLayerId, setActiveLassoLayerId] = useState< - string | undefined - >(); + const [lassoDrawMode, setLassoDrawMode] = useState<'freehand' | 'polygon'>( + 'freehand', + ); + const [selectedLassoLayerIds, setSelectedLassoLayerIds] = useState( + [], + ); + // Stores the completed lasso polygon for point-in-polygon queries (next phase) + const [_lassoPolygon, setLassoPolygon] = useState(null); + + // Default pre-select the first layer when layers load + useEffect(() => { + if (lassoLayers.length > 0 && selectedLassoLayerIds.length === 0) { + setSelectedLassoLayerIds([lassoLayers[0].id]); + } + }, [lassoLayers]); // eslint-disable-line react-hooks/exhaustive-deps const handleLassoToggle = useCallback(() => { setLassoIsActive(false); - setActiveLassoLayerId(undefined); + setSelectedLassoLayerIds([]); + setLassoPolygon(null); + }, []); + + const handleLassoLayerToggle = useCallback((layerId: string) => { + setSelectedLassoLayerIds(prev => + prev.includes(layerId) + ? prev.filter(id => id !== layerId) + : [...prev, layerId], + ); }, []); - const handleLassoLayerSelect = useCallback((layerId: string) => { - setActiveLassoLayerId(layerId); + const handleLassoActivate = useCallback(() => { setLassoIsActive(true); + setLassoPolygon(null); + }, []); + + // Called by EditableGeoJsonLayer when freehand polygon drawing completes + const handleLassoComplete = useCallback((polygon: Coordinate[]) => { + setLassoPolygon(polygon); }, []); const handleRulerToggle = useCallback(() => { @@ -1036,6 +1063,9 @@ const DeckMulti = (props: DeckMultiProps) => { isDragging: false, }; } + // Deactivate lasso when activating ruler + setLassoIsActive(false); + setLassoPolygon(null); return { startPoint: null, endPoint: null, @@ -1085,21 +1115,27 @@ const DeckMulti = (props: DeckMultiProps) => { }); }, []); - // Handle escape key to exit ruler mode + // Handle escape key to exit ruler or lasso mode useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { - if (e.key === 'Escape' && measureState.isActive) { - setMeasureState({ - startPoint: null, - endPoint: null, - isActive: false, - isDragging: false, - }); + if (e.key === 'Escape') { + if (measureState.isActive) { + setMeasureState({ + startPoint: null, + endPoint: null, + isActive: false, + isDragging: false, + }); + } + if (lassoIsActive) { + setLassoIsActive(false); + setLassoPolygon(null); + } } }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); - }, [measureState.isActive]); + }, [measureState.isActive, lassoIsActive]); // Gate map canvas rendering to prevent a viewport jump when autozoom layers // load. Phase 1 loads autozoom layers first; the canvas stays hidden until @@ -1152,6 +1188,9 @@ const DeckMulti = (props: DeckMultiProps) => { onMeasureDragStart={handleMeasureDragStart} onMeasureDrag={handleMeasureDrag} onMeasureDragEnd={handleMeasureDragEnd} + lassoIsActive={lassoIsActive} + lassoDrawMode={lassoDrawMode} + onLassoComplete={handleLassoComplete} onEmptyClick={handleClosePopup} /> { onRulerToggle={handleRulerToggle} isRulerActive={measureState.isActive} onLassoToggle={handleLassoToggle} + onLassoActivate={handleLassoActivate} isLassoActive={lassoIsActive} lassoLayers={lassoLayers} - activeLassoLayerId={activeLassoLayerId} - onLassoLayerSelect={handleLassoLayerSelect} + activeLassoLayerIds={selectedLassoLayerIds} + onLassoLayerToggle={handleLassoLayerToggle} + lassoDrawMode={lassoDrawMode} + onLassoDrawModeChange={setLassoDrawMode} position="top-right" /> {clickedFeature && ( diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx new file mode 100644 index 0000000000..2282dae601 --- /dev/null +++ b/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx @@ -0,0 +1,111 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { + EditableGeoJsonLayer, + DrawPolygonByDraggingMode, + DrawPolygonMode, + ViewMode, +} from '@deck.gl-community/editable-layers'; +import type { Coordinate } from '../utils/measureDistance'; + +export type LassoDrawMode = 'freehand' | 'polygon'; + +const EMPTY_FEATURE_COLLECTION = { + type: 'FeatureCollection' as const, + features: [] as any[], +}; + +// Custom crosshair cursor for lasso drawing mode +export const LASSO_CURSOR = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Ccircle cx='16' cy='16' r='5' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cline x1='16' y1='8' x2='16' y2='13' stroke='%23000' stroke-width='1.5'/%3E%3Cline x1='16' y1='19' x2='16' y2='24' stroke='%23000' stroke-width='1.5'/%3E%3Cline x1='8' y1='16' x2='13' y2='16' stroke='%23000' stroke-width='1.5'/%3E%3Cline x1='19' y1='16' x2='24' y2='16' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 16 16, crosshair`; + +const DRAW_MODES = { + freehand: DrawPolygonByDraggingMode, + polygon: DrawPolygonMode, +}; + +/** + * Hook to create an EditableGeoJsonLayer for lasso drawing. + * Supports freehand (drag) and point-to-point (click vertices, double-click to close). + */ +export function useLassoLayer( + isActive: boolean, + onPolygonComplete: (polygon: Coordinate[]) => void, + drawMode: LassoDrawMode = 'freehand', +): { layers: any[] } { + const [data, setData] = useState(EMPTY_FEATURE_COLLECTION); + const [mode, setMode] = useState(() => DRAW_MODES[drawMode]); + + // Reset when lasso is activated or deactivated + useEffect(() => { + if (isActive) { + setData(EMPTY_FEATURE_COLLECTION); + setMode(() => DRAW_MODES[drawMode]); + } + }, [isActive]); // eslint-disable-line react-hooks/exhaustive-deps + + // Switch draw mode while active (without resetting polygon data) + useEffect(() => { + if (isActive) { + setMode(() => DRAW_MODES[drawMode]); + } + }, [drawMode, isActive]); + + const handleEdit = useCallback( + ({ updatedData, editType }: { updatedData: any; editType: string }) => { + setData(updatedData); + if (editType === 'addFeature') { + // Polygon drawing complete — extract coordinates and switch to view mode + const lastFeature = + updatedData.features[updatedData.features.length - 1]; + const coords: number[][] = lastFeature.geometry.coordinates[0]; + setMode(() => ViewMode); + onPolygonComplete(coords.map(c => [c[0], c[1]] as Coordinate)); + } + }, + [onPolygonComplete], + ); + + const layers = useMemo(() => { + if (!isActive) return []; + + return [ + new EditableGeoJsonLayer({ + id: 'lasso-editable-layer', + data, + mode, + selectedFeatureIndexes: [], + onEdit: handleEdit, + + // Completed polygon styling + getFillColor: [66, 133, 244, 40], + getLineColor: [50, 50, 50, 200], + lineWidthMinPixels: 2, + + // Tentative polygon styling (while drawing) + getTentativeFillColor: [66, 133, 244, 20], + getTentativeLineColor: [50, 50, 50, 180], + + pickable: true, + }), + ]; + }, [isActive, data, mode, handleEdit]); + + return { layers }; +} diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx index 146b4d5765..d0e35c3472 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx @@ -19,6 +19,8 @@ import { memo, useState, useRef, useEffect } from 'react'; import { styled } from '@superset-ui/core'; +import type { LassoDrawMode } from './LassoOverlay'; + export type LassoLayer = { id: string; name: string }; export type MapControlsProps = { @@ -28,10 +30,13 @@ export type MapControlsProps = { onRulerToggle: () => void; isRulerActive: boolean; onLassoToggle: () => void; + onLassoActivate?: () => void; isLassoActive: boolean; lassoLayers?: LassoLayer[]; - activeLassoLayerId?: string; - onLassoLayerSelect?: (layerId: string) => void; + activeLassoLayerIds?: string[]; + onLassoLayerToggle?: (layerId: string) => void; + lassoDrawMode?: LassoDrawMode; + onLassoDrawModeChange?: (mode: LassoDrawMode) => void; position?: 'top-left' | 'top-right'; }; @@ -97,7 +102,7 @@ const DropdownPanel = styled.div( position: absolute; top: calc(100% + 6px); right: 0; - min-width: 180px; + min-width: 200px; background: ${theme.colorBgElevated}; border: 1px solid ${theme.colorBorderSecondary}; border-radius: 6px; @@ -108,6 +113,9 @@ const DropdownPanel = styled.div( const DropdownHeader = styled.div( ({ theme }) => ` + display: flex; + align-items: center; + justify-content: space-between; padding: 8px 12px 6px; font-size: 11px; font-weight: 600; @@ -117,40 +125,131 @@ const DropdownHeader = styled.div( `, ); -const DropdownItem = styled.button<{ $isActive?: boolean }>( - ({ theme, $isActive }) => ` +const CloseButton = styled.button( + ({ theme }) => ` + display: flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + padding: 0; + background: transparent; + border: none; + cursor: pointer; + font-size: 14px; + line-height: 1; + color: ${theme.colorTextSecondary}; + + &:hover { + color: ${theme.colorText}; + } +`, +); + +const DropdownItem = styled.button( + ({ theme }) => ` display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 12px; - background: ${$isActive ? theme.colorPrimaryBg : 'transparent'}; + background: transparent; border: none; cursor: pointer; font-family: inherit; font-size: 13px; - color: ${$isActive ? theme.colorPrimary : theme.colorText}; + color: ${theme.colorText}; text-align: left; white-space: nowrap; + &:hover { + background: ${theme.colorBgTextHover}; + } +`, +); + +const ModeToggleSection = styled.div( + ({ theme }) => ` + display: flex; + gap: 4px; + padding: 8px 12px; + border-top: 1px solid ${theme.colorBorderSecondary}; +`, +); + +const ModeButton = styled.button<{ $isActive?: boolean }>( + ({ theme, $isActive }) => ` + display: flex; + align-items: center; + gap: 4px; + flex: 1; + padding: 4px 8px; + background: ${$isActive ? theme.colorPrimaryBg : 'transparent'}; + border: none; + border-radius: 4px; + cursor: pointer; + font-family: inherit; + font-size: 11px; + color: ${$isActive ? theme.colorPrimary : theme.colorTextSecondary}; + white-space: nowrap; + &:hover { background: ${$isActive ? theme.colorPrimaryBgHover : theme.colorBgTextHover}; } `, ); -const CheckIcon = () => ( - - +const FreehandIcon = () => ( + + + +); + +const PolygonIcon = () => ( + + + + + + + +); + +const CheckboxIcon = ({ checked }: { checked: boolean }) => ( + + + {checked && ( + + )} ); @@ -214,16 +313,20 @@ const MapControls = ({ onRulerToggle, isRulerActive, onLassoToggle, + onLassoActivate, isLassoActive, lassoLayers = [], - activeLassoLayerId, - onLassoLayerSelect, + activeLassoLayerIds = [], + onLassoLayerToggle, + lassoDrawMode = 'freehand', + onLassoDrawModeChange, position = 'top-left', }: MapControlsProps) => { const [isDropdownOpen, setIsDropdownOpen] = useState(false); const containerRef = useRef(null); + const hasMultipleLayers = lassoLayers.length > 1; - // Close dropdown on outside click + // Close dropdown on outside click — activates lasso useEffect(() => { if (!isDropdownOpen) return undefined; const handleOutsideClick = (e: MouseEvent) => { @@ -232,26 +335,39 @@ const MapControls = ({ !containerRef.current.contains(e.target as Node) ) { setIsDropdownOpen(false); + // Multi-layer requires at least one layer selected; single-layer always activates + if (!hasMultipleLayers || activeLassoLayerIds.length > 0) { + onLassoActivate?.(); + } } }; document.addEventListener('mousedown', handleOutsideClick); return () => document.removeEventListener('mousedown', handleOutsideClick); - }, [isDropdownOpen]); + }, [ + isDropdownOpen, + hasMultipleLayers, + activeLassoLayerIds.length, + onLassoActivate, + ]); const handleLassoButtonClick = () => { if (isLassoActive) { - // Deactivate lasso onLassoToggle(); setIsDropdownOpen(false); } else { - // Open layer picker setIsDropdownOpen(prev => !prev); } }; - const handleLayerSelect = (layerId: string) => { + const handleLayerToggle = (layerId: string) => { + onLassoLayerToggle?.(layerId); + }; + + const handleCloseDropdown = () => { setIsDropdownOpen(false); - onLassoLayerSelect?.(layerId); + if (!hasMultipleLayers || activeLassoLayerIds.length > 0) { + onLassoActivate?.(); + } }; return ( @@ -284,22 +400,41 @@ const MapControls = ({ - {isDropdownOpen && lassoLayers.length > 0 && ( + {isDropdownOpen && ( - Select layer - {lassoLayers.map(layer => ( - handleLayerSelect(layer.id)} + + {hasMultipleLayers ? 'Select layers' : 'Lasso mode'} + + ✕ + + + {hasMultipleLayers && + lassoLayers.map(layer => { + const isChecked = activeLassoLayerIds.includes(layer.id); + return ( + handleLayerToggle(layer.id)} + > + + {layer.name} + + ); + })} + + onLassoDrawModeChange?.('freehand')} + > + Freehand + + onLassoDrawModeChange?.('polygon')} > - {layer.id === activeLassoLayerId && } - {layer.id !== activeLassoLayerId && ( - - )} - {layer.name} - - ))} + Point-to-point + + )} diff --git a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx index 935f1abc14..35136b4114 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx @@ -947,6 +947,25 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { isDragging: false, }); + // Lasso state (single-layer: no dropdown, just toggle) + const [lassoIsActive, setLassoIsActive] = useState(false); + const [lassoDrawMode, setLassoDrawMode] = useState<'freehand' | 'polygon'>( + 'freehand', + ); + + const handleLassoToggle = useCallback(() => { + setLassoIsActive(false); + }, []); + + const handleLassoActivate = useCallback(() => { + setLassoIsActive(true); + }, []); + + const handleLassoComplete = useCallback((polygon: [number, number][]) => { + // TODO: point-in-polygon query + results bar + console.log('Lasso complete (single layer):', polygon); + }, []); + // Don't show popup when measurement mode is active const handleFeatureClick = useCallback( (info: any) => { @@ -1204,6 +1223,9 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { onMeasureDragStart={handleMeasureDragStart} onMeasureDrag={handleMeasureDrag} onMeasureDragEnd={handleMeasureDragEnd} + lassoIsActive={lassoIsActive} + lassoDrawMode={lassoDrawMode} + onLassoComplete={handleLassoComplete} onEmptyClick={handleClosePopup} /> { onResetView={handleResetView} onRulerToggle={handleRulerToggle} isRulerActive={measureState.isActive} + onLassoToggle={handleLassoToggle} + onLassoActivate={handleLassoActivate} + isLassoActive={lassoIsActive} + lassoDrawMode={lassoDrawMode} + onLassoDrawModeChange={setLassoDrawMode} position="top-right" - onLassoToggle={function (): void { - throw new Error('Function not implemented.'); - }} - isLassoActive={false} /> = {}) { + return renderWithTheme(); +} + +beforeEach(() => { + jest.clearAllMocks(); +}); + +describe('MapControls', () => { + it('renders all toolbar buttons', () => { + renderMapControls(); + expect(screen.getByTitle('Reset view')).toBeInTheDocument(); + expect(screen.getByTitle('Zoom out')).toBeInTheDocument(); + expect(screen.getByTitle('Zoom in')).toBeInTheDocument(); + expect(screen.getByTitle('Measure distance')).toBeInTheDocument(); + expect( + screen.getByTitle('Lasso select features'), + ).toBeInTheDocument(); + }); + + it('calls onZoomIn, onZoomOut, onResetView on click', () => { + const onZoomIn = jest.fn(); + const onZoomOut = jest.fn(); + const onResetView = jest.fn(); + renderMapControls({ onZoomIn, onZoomOut, onResetView }); + + userEvent.click(screen.getByTitle('Zoom in')); + expect(onZoomIn).toHaveBeenCalledTimes(1); + + userEvent.click(screen.getByTitle('Zoom out')); + expect(onZoomOut).toHaveBeenCalledTimes(1); + + userEvent.click(screen.getByTitle('Reset view')); + expect(onResetView).toHaveBeenCalledTimes(1); + }); + + it('calls onRulerToggle on ruler button click', () => { + const onRulerToggle = jest.fn(); + renderMapControls({ onRulerToggle }); + + userEvent.click(screen.getByTitle('Measure distance')); + expect(onRulerToggle).toHaveBeenCalledTimes(1); + }); + + it('shows "Exit measure mode" title when ruler is active', () => { + renderMapControls({ isRulerActive: true }); + expect( + screen.getByTitle('Exit measure mode (Esc)'), + ).toBeInTheDocument(); + }); +}); + +describe('Lasso — single-layer (no lassoLayers)', () => { + it('opens dropdown with "Lasso mode" header on click', () => { + renderMapControls(); + + expect(screen.queryByText('Lasso mode')).not.toBeInTheDocument(); + + userEvent.click(screen.getByTitle('Lasso select features')); + expect(screen.getByText('Lasso mode')).toBeInTheDocument(); + }); + + it('shows mode toggle buttons in dropdown', () => { + renderMapControls(); + + userEvent.click(screen.getByTitle('Lasso select features')); + expect(screen.getByText('Freehand')).toBeInTheDocument(); + expect(screen.getByText('Point-to-point')).toBeInTheDocument(); + }); + + it('does not show layer checkboxes', () => { + renderMapControls(); + + userEvent.click(screen.getByTitle('Lasso select features')); + expect(screen.queryByText('Select layers')).not.toBeInTheDocument(); + }); + + it('calls onLassoActivate when close button clicked', () => { + const onLassoActivate = jest.fn(); + renderMapControls({ onLassoActivate }); + + userEvent.click(screen.getByTitle('Lasso select features')); + userEvent.click(screen.getByTitle('Close')); + expect(onLassoActivate).toHaveBeenCalledTimes(1); + }); + + it('calls onLassoDrawModeChange when mode button clicked', () => { + const onLassoDrawModeChange = jest.fn(); + renderMapControls({ onLassoDrawModeChange, lassoDrawMode: 'freehand' }); + + userEvent.click(screen.getByTitle('Lasso select features')); + userEvent.click(screen.getByText('Point-to-point')); + expect(onLassoDrawModeChange).toHaveBeenCalledWith('polygon'); + }); +}); + +describe('Lasso — multi-layer', () => { + const layers = [ + { id: '1', name: 'Burn Areas' }, + { id: '2', name: 'Program Offices' }, + { id: '3', name: 'Air Quality' }, + ]; + + it('opens dropdown with "Select layers" header and layer list', () => { + renderMapControls({ lassoLayers: layers }); + + userEvent.click(screen.getByTitle('Lasso select features')); + expect(screen.getByText('Select layers')).toBeInTheDocument(); + expect(screen.getByText('Burn Areas')).toBeInTheDocument(); + expect(screen.getByText('Program Offices')).toBeInTheDocument(); + expect(screen.getByText('Air Quality')).toBeInTheDocument(); + }); + + it('calls onLassoLayerToggle when a layer is clicked', () => { + const onLassoLayerToggle = jest.fn(); + renderMapControls({ lassoLayers: layers, onLassoLayerToggle }); + + userEvent.click(screen.getByTitle('Lasso select features')); + userEvent.click(screen.getByText('Program Offices')); + expect(onLassoLayerToggle).toHaveBeenCalledWith('2'); + }); + + it('calls onLassoActivate on close when layers are selected', () => { + const onLassoActivate = jest.fn(); + renderMapControls({ + lassoLayers: layers, + activeLassoLayerIds: ['2'], + onLassoActivate, + }); + + userEvent.click(screen.getByTitle('Lasso select features')); + userEvent.click(screen.getByTitle('Close')); + expect(onLassoActivate).toHaveBeenCalledTimes(1); + }); + + it('does NOT call onLassoActivate on close when no layers selected', () => { + const onLassoActivate = jest.fn(); + renderMapControls({ + lassoLayers: layers, + activeLassoLayerIds: [], + onLassoActivate, + }); + + userEvent.click(screen.getByTitle('Lasso select features')); + userEvent.click(screen.getByTitle('Close')); + expect(onLassoActivate).not.toHaveBeenCalled(); + }); + + it('shows mode toggle alongside layer list', () => { + renderMapControls({ lassoLayers: layers }); + + userEvent.click(screen.getByTitle('Lasso select features')); + expect(screen.getByText('Freehand')).toBeInTheDocument(); + expect(screen.getByText('Point-to-point')).toBeInTheDocument(); + }); +}); + +describe('Lasso — active state', () => { + it('shows "Exit lasso mode" title when active', () => { + renderMapControls({ isLassoActive: true }); + expect( + screen.getByTitle('Exit lasso mode (Esc)'), + ).toBeInTheDocument(); + }); + + it('calls onLassoToggle (deactivate) when button clicked while active', () => { + const onLassoToggle = jest.fn(); + renderMapControls({ isLassoActive: true, onLassoToggle }); + + userEvent.click(screen.getByTitle('Exit lasso mode (Esc)')); + expect(onLassoToggle).toHaveBeenCalledTimes(1); + }); + + it('does not open dropdown when clicking to deactivate', () => { + renderMapControls({ isLassoActive: true }); + + userEvent.click(screen.getByTitle('Exit lasso mode (Esc)')); + expect(screen.queryByText('Lasso mode')).not.toBeInTheDocument(); + expect(screen.queryByText('Select layers')).not.toBeInTheDocument(); + }); +}); diff --git a/superset-frontend/webpack.config.js b/superset-frontend/webpack.config.js index 7269f9db3b..adecb5c810 100644 --- a/superset-frontend/webpack.config.js +++ b/superset-frontend/webpack.config.js @@ -356,7 +356,7 @@ const config = { }, }, { - test: /node_modules\/(@deck\.gl|@luma\.gl).*\.js$/, + test: /node_modules\/(@deck\.gl|@deck\.gl-community|@luma\.gl|@turf).*\.js$/, loader: 'imports-loader', options: { additionalCode: 'var module = module || {exports: {}};', From 22014f52c978263881c131c8dd7cdb6a606f731b Mon Sep 17 00:00:00 2001 From: lhawkins Date: Mon, 23 Mar 2026 15:09:20 -0400 Subject: [PATCH 05/37] refactor: Extract useLassoSelection hook and fix lasso/ruler bugs Extract duplicated lasso state management from GeoSetLayer.tsx and Multi.tsx into a shared useLassoSelection hook. Fix escape key not exiting lasso mode in single-layer charts, and add reciprocal mode deactivation so lasso and ruler can never be active simultaneously. Replace `any` type on LassoOverlay mode state with explicit union type. Add tests for useLassoSelection (14) and useLassoLayer (7) hooks. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/GeoSetMultiMap/Multi.tsx | 93 ++++----- .../src/components/LassoOverlay.tsx | 9 +- .../src/hooks/useLassoSelection.ts | 126 +++++++++++++ .../src/layers/GeoSetLayer/GeoSetLayer.tsx | 46 ++--- .../test/components/LassoOverlay.test.ts | 137 ++++++++++++++ .../test/hooks/useLassoSelection.test.ts | 177 ++++++++++++++++++ wiki/Development-Guide.md | 1 + 7 files changed, 507 insertions(+), 82 deletions(-) create mode 100644 superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts create mode 100644 superset-frontend/plugins/geoset-map-chart/test/components/LassoOverlay.test.ts create mode 100644 superset-frontend/plugins/geoset-map-chart/test/hooks/useLassoSelection.test.ts diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx index 5008cc8262..6df5433268 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx @@ -49,6 +49,7 @@ import type { CategoryEntry, LegendEntry } from '../types'; import { useGroupedLegend } from '../utils/hooks'; import MapControls from '../components/MapControls'; import type { Coordinate } from '../utils/measureDistance'; +import { useLassoSelection } from '../hooks/useLassoSelection'; import { CategoryState, MetricLegend, RGBAColor } from '../utils/colors'; import { getGeometryType } from '../utils/dataProcessing'; import { fetchMapboxApiKey, getCachedMapboxApiKey } from '../utils/mapboxApi'; @@ -1011,47 +1012,27 @@ const DeckMulti = (props: DeckMultiProps) => { // Keep ref in sync with measure state for use in callbacks measureActiveRef.current = measureState.isActive; - // Lasso selection state - const [lassoIsActive, setLassoIsActive] = useState(false); - const [lassoDrawMode, setLassoDrawMode] = useState<'freehand' | 'polygon'>( - 'freehand', - ); - const [selectedLassoLayerIds, setSelectedLassoLayerIds] = useState( - [], - ); - // Stores the completed lasso polygon for point-in-polygon queries (next phase) - const [_lassoPolygon, setLassoPolygon] = useState(null); - - // Default pre-select the first layer when layers load - useEffect(() => { - if (lassoLayers.length > 0 && selectedLassoLayerIds.length === 0) { - setSelectedLassoLayerIds([lassoLayers[0].id]); - } - }, [lassoLayers]); // eslint-disable-line react-hooks/exhaustive-deps - - const handleLassoToggle = useCallback(() => { - setLassoIsActive(false); - setSelectedLassoLayerIds([]); - setLassoPolygon(null); - }, []); - - const handleLassoLayerToggle = useCallback((layerId: string) => { - setSelectedLassoLayerIds(prev => - prev.includes(layerId) - ? prev.filter(id => id !== layerId) - : [...prev, layerId], - ); - }, []); - - const handleLassoActivate = useCallback(() => { - setLassoIsActive(true); - setLassoPolygon(null); - }, []); - - // Called by EditableGeoJsonLayer when freehand polygon drawing completes - const handleLassoComplete = useCallback((polygon: Coordinate[]) => { - setLassoPolygon(polygon); - }, []); + const { + lassoIsActive, + lassoDrawMode, + setLassoDrawMode, + selectedLassoLayerIds, + handleLassoToggle, + handleLassoActivate, + handleLassoComplete, + handleLassoLayerToggle, + deactivateLasso, + } = useLassoSelection({ + availableLayers: lassoLayers, + onActivate: () => { + setMeasureState({ + startPoint: null, + endPoint: null, + isActive: false, + isDragging: false, + }); + }, + }); const handleRulerToggle = useCallback(() => { setMeasureState(prev => { @@ -1063,9 +1044,7 @@ const DeckMulti = (props: DeckMultiProps) => { isDragging: false, }; } - // Deactivate lasso when activating ruler - setLassoIsActive(false); - setLassoPolygon(null); + deactivateLasso(); return { startPoint: null, endPoint: null, @@ -1073,7 +1052,7 @@ const DeckMulti = (props: DeckMultiProps) => { isDragging: false, }; }); - }, []); + }, [deactivateLasso]); const handleMeasureClick = useCallback((coordinate: [number, number]) => { setMeasureState(prev => { @@ -1115,27 +1094,21 @@ const DeckMulti = (props: DeckMultiProps) => { }); }, []); - // Handle escape key to exit ruler or lasso mode + // Handle escape key to exit ruler mode (lasso escape is handled by useLassoSelection) useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { - if (e.key === 'Escape') { - if (measureState.isActive) { - setMeasureState({ - startPoint: null, - endPoint: null, - isActive: false, - isDragging: false, - }); - } - if (lassoIsActive) { - setLassoIsActive(false); - setLassoPolygon(null); - } + if (e.key === 'Escape' && measureState.isActive) { + setMeasureState({ + startPoint: null, + endPoint: null, + isActive: false, + isDragging: false, + }); } }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); - }, [measureState.isActive, lassoIsActive]); + }, [measureState.isActive]); // Gate map canvas rendering to prevent a viewport jump when autozoom layers // load. Phase 1 loads autozoom layers first; the canvas stays hidden until diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx index 2282dae601..7e901c24f0 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx @@ -27,6 +27,11 @@ import type { Coordinate } from '../utils/measureDistance'; export type LassoDrawMode = 'freehand' | 'polygon'; +type EditModeConstructor = + | typeof DrawPolygonByDraggingMode + | typeof DrawPolygonMode + | typeof ViewMode; + const EMPTY_FEATURE_COLLECTION = { type: 'FeatureCollection' as const, features: [] as any[], @@ -50,7 +55,9 @@ export function useLassoLayer( drawMode: LassoDrawMode = 'freehand', ): { layers: any[] } { const [data, setData] = useState(EMPTY_FEATURE_COLLECTION); - const [mode, setMode] = useState(() => DRAW_MODES[drawMode]); + const [mode, setMode] = useState( + () => DRAW_MODES[drawMode], + ); // Reset when lasso is activated or deactivated useEffect(() => { diff --git a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts new file mode 100644 index 0000000000..b48eae5ba9 --- /dev/null +++ b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts @@ -0,0 +1,126 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { useCallback, useEffect, useRef, useState } from 'react'; +import type { LassoDrawMode } from '../components/LassoOverlay'; +import type { Coordinate } from '../utils/measureDistance'; +import type { LassoLayer } from '../components/MapControls'; + +export type UseLassoSelectionOptions = { + /** Available layers for multi-layer selection. Omit or pass empty for single-layer. */ + availableLayers?: LassoLayer[]; + /** Called when lasso polygon drawing completes. */ + onPolygonComplete?: (polygon: Coordinate[]) => void; + /** Called when lasso is activated (useful for deactivating other modes like ruler). */ + onActivate?: () => void; +}; + +export type UseLassoSelectionResult = { + lassoIsActive: boolean; + lassoDrawMode: LassoDrawMode; + setLassoDrawMode: (mode: LassoDrawMode) => void; + selectedLassoLayerIds: string[]; + handleLassoToggle: () => void; + handleLassoActivate: () => void; + handleLassoComplete: (polygon: Coordinate[]) => void; + handleLassoLayerToggle: (layerId: string) => void; + deactivateLasso: () => void; +}; + +export function useLassoSelection( + options: UseLassoSelectionOptions = {}, +): UseLassoSelectionResult { + const { availableLayers = [] } = options; + + // Use refs for callbacks to avoid stale closures without re-triggering effects + const onPolygonCompleteRef = useRef(options.onPolygonComplete); + onPolygonCompleteRef.current = options.onPolygonComplete; + const onActivateRef = useRef(options.onActivate); + onActivateRef.current = options.onActivate; + + const [lassoIsActive, setLassoIsActive] = useState(false); + const [lassoDrawMode, setLassoDrawMode] = useState('freehand'); + const [selectedLassoLayerIds, setSelectedLassoLayerIds] = useState( + [], + ); + + // Auto-select the first layer when available layers load and none are selected. + // Serialize IDs as the dependency so the effect only fires when actual layers change. + const availableLayerIds = availableLayers.map(l => l.id).join(','); + useEffect(() => { + if (availableLayers.length > 0 && selectedLassoLayerIds.length === 0) { + setSelectedLassoLayerIds([availableLayers[0].id]); + } + }, [availableLayerIds]); // eslint-disable-line react-hooks/exhaustive-deps + + // Deactivate lasso without clearing layer selections (soft deactivation for mode switching) + const deactivateLasso = useCallback(() => { + setLassoIsActive(false); + }, []); + + // Toggle lasso off — full reset including layer selections + const handleLassoToggle = useCallback(() => { + setLassoIsActive(false); + setSelectedLassoLayerIds([]); + }, []); + + // Activate lasso drawing and notify parent (e.g. to deactivate ruler) + const handleLassoActivate = useCallback(() => { + onActivateRef.current?.(); + setLassoIsActive(true); + }, []); + + // Forward completed polygon to consumer + const handleLassoComplete = useCallback((polygon: Coordinate[]) => { + onPolygonCompleteRef.current?.(polygon); + }, []); + + // Toggle a layer in/out of the multi-layer selection + const handleLassoLayerToggle = useCallback((layerId: string) => { + setSelectedLassoLayerIds(prev => + prev.includes(layerId) + ? prev.filter(id => id !== layerId) + : [...prev, layerId], + ); + }, []); + + // Escape key exits lasso mode + useEffect(() => { + if (!lassoIsActive) return undefined; + + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Escape') { + setLassoIsActive(false); + } + }; + document.addEventListener('keydown', handleKeyDown); + return () => document.removeEventListener('keydown', handleKeyDown); + }, [lassoIsActive]); + + return { + lassoIsActive, + lassoDrawMode, + setLassoDrawMode, + selectedLassoLayerIds, + handleLassoToggle, + handleLassoActivate, + handleLassoComplete, + handleLassoLayerToggle, + deactivateLasso, + }; +} diff --git a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx index 35136b4114..689f0c346d 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx @@ -18,6 +18,7 @@ * under the License. */ import { memo, useCallback, useMemo, useRef, useState, useEffect } from 'react'; +import { useLassoSelection } from '../../hooks/useLassoSelection'; import { GeoJsonLayer, IconLayer, @@ -947,24 +948,28 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { isDragging: false, }); - // Lasso state (single-layer: no dropdown, just toggle) - const [lassoIsActive, setLassoIsActive] = useState(false); - const [lassoDrawMode, setLassoDrawMode] = useState<'freehand' | 'polygon'>( - 'freehand', - ); - - const handleLassoToggle = useCallback(() => { - setLassoIsActive(false); - }, []); - - const handleLassoActivate = useCallback(() => { - setLassoIsActive(true); - }, []); - - const handleLassoComplete = useCallback((polygon: [number, number][]) => { - // TODO: point-in-polygon query + results bar - console.log('Lasso complete (single layer):', polygon); - }, []); + const { + lassoIsActive, + lassoDrawMode, + setLassoDrawMode, + handleLassoToggle, + handleLassoActivate, + handleLassoComplete, + deactivateLasso, + } = useLassoSelection({ + onPolygonComplete: polygon => { + // TODO: point-in-polygon query + results bar + console.log('Lasso complete (single layer):', polygon); + }, + onActivate: () => { + setMeasureState({ + startPoint: null, + endPoint: null, + isActive: false, + isDragging: false, + }); + }, + }); // Don't show popup when measurement mode is active const handleFeatureClick = useCallback( @@ -980,7 +985,6 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { const handleRulerToggle = useCallback(() => { setMeasureState(prev => { if (prev.isActive) { - // Exiting ruler mode - clear points return { startPoint: null, endPoint: null, @@ -988,7 +992,7 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { isDragging: false, }; } - // Entering ruler mode + deactivateLasso(); return { startPoint: null, endPoint: null, @@ -996,7 +1000,7 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { isDragging: false, }; }); - }, []); + }, [deactivateLasso]); const handleMeasureClick = useCallback((coordinate: Coordinate) => { setMeasureState(prev => { diff --git a/superset-frontend/plugins/geoset-map-chart/test/components/LassoOverlay.test.ts b/superset-frontend/plugins/geoset-map-chart/test/components/LassoOverlay.test.ts new file mode 100644 index 0000000000..40b66e3752 --- /dev/null +++ b/superset-frontend/plugins/geoset-map-chart/test/components/LassoOverlay.test.ts @@ -0,0 +1,137 @@ +import { renderHook, act } from '@testing-library/react-hooks'; + +// Mock the editable-layers library — EditableGeoJsonLayer requires WebGL. +// Use a global ref so the mock factory (which is hoisted) can access it. +let mockLayerCalls = []; + +jest.mock('@deck.gl-community/editable-layers', () => { + class FakeDrawPolygonByDraggingMode {} + class FakeDrawPolygonMode {} + class FakeViewMode {} + + function MockEditableGeoJsonLayer(props) { + mockLayerCalls.push(props); + return { id: props.id, props }; + } + + return { + EditableGeoJsonLayer: MockEditableGeoJsonLayer, + DrawPolygonByDraggingMode: FakeDrawPolygonByDraggingMode, + DrawPolygonMode: FakeDrawPolygonMode, + ViewMode: FakeViewMode, + }; +}); + +import { useLassoLayer } from '../../src/components/LassoOverlay'; + +beforeEach(() => { + mockLayerCalls = []; +}); + +describe('useLassoLayer', () => { + it('returns empty layers when inactive', () => { + const onComplete = jest.fn(); + const { result } = renderHook(() => useLassoLayer(false, onComplete)); + expect(result.current.layers).toEqual([]); + }); + + it('returns one layer when active', () => { + const onComplete = jest.fn(); + const { result } = renderHook(() => useLassoLayer(true, onComplete)); + expect(result.current.layers).toHaveLength(1); + expect(mockLayerCalls.length).toBeGreaterThan(0); + }); + + it('creates layer with correct id', () => { + const onComplete = jest.fn(); + renderHook(() => useLassoLayer(true, onComplete)); + expect(mockLayerCalls[0]).toEqual( + expect.objectContaining({ id: 'lasso-editable-layer' }), + ); + }); + + it('calls onPolygonComplete when addFeature edit occurs', () => { + const onComplete = jest.fn(); + renderHook(() => useLassoLayer(true, onComplete)); + + const { onEdit } = mockLayerCalls[0]; + + const fakePolygon = { + type: 'FeatureCollection', + features: [ + { + geometry: { + coordinates: [ + [ + [10, 20], + [30, 40], + [50, 60], + [10, 20], + ], + ], + }, + }, + ], + }; + + act(() => { + onEdit({ updatedData: fakePolygon, editType: 'addFeature' }); + }); + + expect(onComplete).toHaveBeenCalledWith([ + [10, 20], + [30, 40], + [50, 60], + [10, 20], + ]); + }); + + it('does not call onPolygonComplete for non-addFeature edits', () => { + const onComplete = jest.fn(); + renderHook(() => useLassoLayer(true, onComplete)); + + const { onEdit } = mockLayerCalls[0]; + + act(() => { + onEdit({ + updatedData: { type: 'FeatureCollection', features: [] }, + editType: 'movePosition', + }); + }); + + expect(onComplete).not.toHaveBeenCalled(); + }); + + it('resets data when transitioning from inactive to active', () => { + const onComplete = jest.fn(); + const { rerender } = renderHook( + ({ active }) => useLassoLayer(active, onComplete), + { initialProps: { active: false } }, + ); + + mockLayerCalls = []; + rerender({ active: true }); + + expect(mockLayerCalls[0]).toEqual( + expect.objectContaining({ + data: expect.objectContaining({ + type: 'FeatureCollection', + features: [], + }), + }), + ); + }); + + it('returns empty layers when transitioning from active to inactive', () => { + const onComplete = jest.fn(); + const { result, rerender } = renderHook( + ({ active }) => useLassoLayer(active, onComplete), + { initialProps: { active: true } }, + ); + + expect(result.current.layers).toHaveLength(1); + + rerender({ active: false }); + expect(result.current.layers).toEqual([]); + }); +}); diff --git a/superset-frontend/plugins/geoset-map-chart/test/hooks/useLassoSelection.test.ts b/superset-frontend/plugins/geoset-map-chart/test/hooks/useLassoSelection.test.ts new file mode 100644 index 0000000000..3fbfad5904 --- /dev/null +++ b/superset-frontend/plugins/geoset-map-chart/test/hooks/useLassoSelection.test.ts @@ -0,0 +1,177 @@ +import { renderHook, act } from '@testing-library/react-hooks'; +import { useLassoSelection } from '../../src/hooks/useLassoSelection'; + +describe('useLassoSelection', () => { + it('returns correct initial state', () => { + const { result } = renderHook(() => useLassoSelection()); + expect(result.current.lassoIsActive).toBe(false); + expect(result.current.lassoDrawMode).toBe('freehand'); + expect(result.current.selectedLassoLayerIds).toEqual([]); + }); + + it('activates lasso on handleLassoActivate', () => { + const { result } = renderHook(() => useLassoSelection()); + act(() => result.current.handleLassoActivate()); + expect(result.current.lassoIsActive).toBe(true); + }); + + it('calls onActivate callback when activated', () => { + const onActivate = jest.fn(); + const { result } = renderHook(() => useLassoSelection({ onActivate })); + act(() => result.current.handleLassoActivate()); + expect(onActivate).toHaveBeenCalledTimes(1); + }); + + it('deactivates and clears layers on handleLassoToggle', () => { + const { result } = renderHook(() => + useLassoSelection({ + availableLayers: [ + { id: '1', name: 'Layer 1' }, + { id: '2', name: 'Layer 2' }, + ], + }), + ); + + // Activate and verify layer is auto-selected + act(() => result.current.handleLassoActivate()); + expect(result.current.lassoIsActive).toBe(true); + expect(result.current.selectedLassoLayerIds).toEqual(['1']); + + // Toggle off — should clear everything + act(() => result.current.handleLassoToggle()); + expect(result.current.lassoIsActive).toBe(false); + expect(result.current.selectedLassoLayerIds).toEqual([]); + }); + + it('deactivates without clearing layers on deactivateLasso', () => { + const { result } = renderHook(() => + useLassoSelection({ + availableLayers: [{ id: '1', name: 'Layer 1' }], + }), + ); + + act(() => result.current.handleLassoActivate()); + expect(result.current.selectedLassoLayerIds).toEqual(['1']); + + // Soft deactivation — layers preserved + act(() => result.current.deactivateLasso()); + expect(result.current.lassoIsActive).toBe(false); + expect(result.current.selectedLassoLayerIds).toEqual(['1']); + }); + + it('changes draw mode via setLassoDrawMode', () => { + const { result } = renderHook(() => useLassoSelection()); + act(() => result.current.setLassoDrawMode('polygon')); + expect(result.current.lassoDrawMode).toBe('polygon'); + }); + + it('toggles layer ids on handleLassoLayerToggle', () => { + const { result } = renderHook(() => useLassoSelection()); + + act(() => result.current.handleLassoLayerToggle('a')); + expect(result.current.selectedLassoLayerIds).toEqual(['a']); + + act(() => result.current.handleLassoLayerToggle('b')); + expect(result.current.selectedLassoLayerIds).toEqual(['a', 'b']); + + // Toggle 'a' off + act(() => result.current.handleLassoLayerToggle('a')); + expect(result.current.selectedLassoLayerIds).toEqual(['b']); + }); + + it('auto-selects first layer when availableLayers provided', () => { + const { result } = renderHook(() => + useLassoSelection({ + availableLayers: [ + { id: 'x', name: 'X' }, + { id: 'y', name: 'Y' }, + ], + }), + ); + expect(result.current.selectedLassoLayerIds).toEqual(['x']); + }); + + it('does not auto-select when layers are already selected', () => { + const { result } = renderHook(() => + useLassoSelection({ + availableLayers: [{ id: 'x', name: 'X' }], + }), + ); + + // Manually toggle to 'y', then re-render with new available layers + act(() => result.current.handleLassoLayerToggle('y')); + expect(result.current.selectedLassoLayerIds).toContain('y'); + }); + + it('calls onPolygonComplete when handleLassoComplete is called', () => { + const onPolygonComplete = jest.fn(); + const { result } = renderHook(() => + useLassoSelection({ onPolygonComplete }), + ); + const polygon = [ + [0, 0], + [1, 0], + [1, 1], + [0, 0], + ]; + act(() => result.current.handleLassoComplete(polygon)); + expect(onPolygonComplete).toHaveBeenCalledWith(polygon); + }); + + it('deactivates lasso on Escape key', () => { + const { result } = renderHook(() => useLassoSelection()); + + act(() => result.current.handleLassoActivate()); + expect(result.current.lassoIsActive).toBe(true); + + act(() => { + document.dispatchEvent( + new KeyboardEvent('keydown', { key: 'Escape' }), + ); + }); + expect(result.current.lassoIsActive).toBe(false); + }); + + it('does not deactivate on Escape when lasso is inactive', () => { + const { result } = renderHook(() => useLassoSelection()); + expect(result.current.lassoIsActive).toBe(false); + + act(() => { + document.dispatchEvent( + new KeyboardEvent('keydown', { key: 'Escape' }), + ); + }); + // Should still be false, no errors + expect(result.current.lassoIsActive).toBe(false); + }); + + it('does not fire Escape listener after unmount', () => { + const { result, unmount } = renderHook(() => useLassoSelection()); + + act(() => result.current.handleLassoActivate()); + unmount(); + + // Should not throw + document.dispatchEvent( + new KeyboardEvent('keydown', { key: 'Escape' }), + ); + }); + + it('uses latest onPolygonComplete callback without stale closures', () => { + const first = jest.fn(); + const second = jest.fn(); + + const { result, rerender } = renderHook( + ({ cb }) => useLassoSelection({ onPolygonComplete: cb }), + { initialProps: { cb: first } }, + ); + + rerender({ cb: second }); + + const polygon = [[0, 0]]; + act(() => result.current.handleLassoComplete(polygon)); + + expect(first).not.toHaveBeenCalled(); + expect(second).toHaveBeenCalledWith(polygon); + }); +}); diff --git a/wiki/Development-Guide.md b/wiki/Development-Guide.md index f5fea97569..9d0d50116b 100644 --- a/wiki/Development-Guide.md +++ b/wiki/Development-Guide.md @@ -72,6 +72,7 @@ GeoSet/ │ │ └── GeoSetLayer/ # Single-layer chart (deck_geoset_map_layer) │ ├── GeoSetMultiMap/ # Multi-layer chart (deck_geoset_multi_map) │ ├── components/ # Legend, Tooltip, MapControls, etc. +│ ├── hooks/ # Shared React hooks (lasso selection, etc.) │ ├── utils/ # Color utilities, geometry helpers, viewport │ ├── buildQuery.ts # PostGIS query builder │ └── transformProps.ts # Data transformation pipeline From 40fd3511088e4bff93ffb99b34743325154a7b3b Mon Sep 17 00:00:00 2001 From: lhawkins Date: Mon, 23 Mar 2026 17:27:04 -0400 Subject: [PATCH 06/37] feat: Add lasso point-in-polygon selection with CSV/Excel export Wire up lasso polygon completion to filter features using Turf.js point-in-polygon queries. Both single-layer and multi-layer charts now show a results bar with feature count and export options (CSV, Excel via xlsx). Add lassoPolygon, selectedFeatures, and clearSelection state to useLassoSelection hook. Update docs with new utility files and lasso feature in README. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 1 + superset-frontend/package-lock.json | 1794 ++++++----------- superset-frontend/package.json | 4 +- .../plugins/geoset-map-chart/package.json | 4 + .../src/GeoSetMultiMap/Multi.tsx | 49 +- .../src/components/LassoResultsBar.tsx | 220 ++ .../src/hooks/useLassoSelection.ts | 27 +- .../src/layers/GeoSetLayer/GeoSetLayer.tsx | 40 +- .../geoset-map-chart/src/utils/lassoExport.ts | 107 + .../src/utils/lassoSelection.ts | 106 + wiki/Development-Guide.md | 2 + 11 files changed, 1120 insertions(+), 1234 deletions(-) create mode 100644 superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx create mode 100644 superset-frontend/plugins/geoset-map-chart/src/utils/lassoExport.ts create mode 100644 superset-frontend/plugins/geoset-map-chart/src/utils/lassoSelection.ts diff --git a/README.md b/README.md index 1fdb778888..de70daa9b0 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ GeoSet bridges the gap between Superset and GIS tooling. This is accomplished by - Point size scaling by value (number or percentile bounds) - Collapsible legend with layer toggling and dynamic iconography - Native dashboard integration +- Lasso select with CSV/Excel export - Text Overlay Formatting

diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index fb7eb02242..9dc9042b26 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -20,6 +20,7 @@ "@emotion/cache": "^11.4.0", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", + "@material-ui/core": "^4.12.4", "@reduxjs/toolkit": "^1.9.3", "@rjsf/core": "^5.21.1", "@rjsf/utils": "^5.24.3", @@ -133,6 +134,7 @@ "rison": "^0.1.1", "scroll-into-view-if-needed": "^3.1.0", "simple-zstd": "^1.4.2", + "sprintf-js": "^1.1.3", "stream-browserify": "^3.0.0", "tinycolor2": "^1.4.2", "urijs": "^1.19.8", @@ -1001,7 +1003,6 @@ "version": "1.4.126", "resolved": "https://registry.npmjs.org/@aw-web-design/x-default-browser/-/x-default-browser-1.4.126.tgz", "integrity": "sha512-Xk1sIhyNC/esHGGVjL/niHLowM0csl/kFO5uawBy4IrWwy0o1G8LGt3jP6nmWGz+USxeeqbihAmp/oVZju6wug==", - "dev": true, "license": "MIT", "dependencies": { "default-browser-id": "3.0.0" @@ -1058,7 +1059,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1068,7 +1068,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.28.6", @@ -1099,7 +1098,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1154,7 +1152,6 @@ "version": "7.27.3", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.27.3" @@ -1167,7 +1164,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", @@ -1184,7 +1180,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1194,7 +1189,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -1216,7 +1210,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1226,7 +1219,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -1244,7 +1236,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1254,7 +1245,6 @@ "version": "0.6.5", "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", @@ -1271,7 +1261,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1289,7 +1278,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/@babel/helper-globals": { @@ -1305,7 +1293,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.5", @@ -1332,7 +1319,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", @@ -1350,7 +1336,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.27.1" @@ -1363,7 +1348,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1373,7 +1357,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", @@ -1391,7 +1374,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-member-expression-to-functions": "^7.28.5", @@ -1409,7 +1391,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -1441,7 +1422,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1451,7 +1431,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", @@ -1466,7 +1445,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", @@ -1519,7 +1497,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -1536,7 +1513,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1552,7 +1528,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1568,7 +1543,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -1586,7 +1560,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -1603,7 +1576,6 @@ "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1684,7 +1656,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.28.6.tgz", "integrity": "sha512-D+OrJumc9McXNEBI/JmFnc/0uCM2/Y3PEBG3gfV3QIYkKv5pvnpzFrl1kYCrcHJP8nOeFB/SHi1IHz29pNGuew==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -1700,7 +1671,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -1716,7 +1686,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -1758,7 +1727,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -1884,7 +1852,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -1900,7 +1867,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", @@ -1917,7 +1883,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1933,7 +1898,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.6.tgz", "integrity": "sha512-9knsChgsMzBV5Yh3kkhrZNxH3oCYAfMBkNNaVN4cP2RVlFPe8wYdwwcnOsAbkdDoV9UjFtOXWrWB52M8W4jNeA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -1951,7 +1915,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", @@ -1969,7 +1932,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1985,7 +1947,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -2001,7 +1962,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", @@ -2018,7 +1978,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", @@ -2035,7 +1994,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -2056,7 +2014,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -2073,7 +2030,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -2090,7 +2046,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", @@ -2107,7 +2062,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2123,7 +2077,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.28.6.tgz", "integrity": "sha512-5suVoXjC14lUN6ZL9OLKIHCNVWCrqGqlmEp/ixdXjvgnEl/kauLvvMO/Xw9NyMc95Joj1AeLVPVMvibBgSoFlA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", @@ -2140,7 +2093,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2156,7 +2108,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -2173,7 +2124,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -2189,7 +2139,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2205,7 +2154,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.27.1.tgz", "integrity": "sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -2222,7 +2170,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -2239,7 +2186,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", @@ -2257,7 +2203,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -2273,7 +2218,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2289,7 +2233,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -2305,7 +2248,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2321,7 +2263,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.27.1", @@ -2338,7 +2279,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.28.6", @@ -2355,7 +2295,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.28.3", @@ -2374,7 +2313,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.27.1", @@ -2391,7 +2329,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", @@ -2408,7 +2345,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2424,7 +2360,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -2440,7 +2375,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -2456,7 +2390,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.28.6", @@ -2476,7 +2409,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -2493,7 +2425,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -2509,7 +2440,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -2526,7 +2456,6 @@ "version": "7.27.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2542,7 +2471,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", @@ -2559,7 +2487,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -2577,7 +2504,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2678,7 +2604,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.6.tgz", "integrity": "sha512-eZhoEZHYQLL5uc1gS5e9/oTknS0sSSAtd5TkKMUp3J+S/CaUjagc0kOUPsEbDmMeva0nC3WWl4SxVY6+OBuxfw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -2694,7 +2619,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", @@ -2711,7 +2635,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2758,7 +2681,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2774,7 +2696,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -2791,7 +2712,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2807,7 +2727,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2823,7 +2742,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2839,7 +2757,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -2859,7 +2776,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2875,7 +2791,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", @@ -2892,7 +2807,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", @@ -2909,7 +2823,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", @@ -2943,7 +2856,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.6.tgz", "integrity": "sha512-GaTI4nXDrs7l0qaJ6Rg06dtOXTBCG6TMDB44zbqofCIC4PqC7SEvmFFtpxzCDw9W5aJ7RKVshgXTLvLdBFV/qw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", @@ -3028,7 +2940,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3038,7 +2949,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.27.1.tgz", "integrity": "sha512-ez3a2it5Fn6P54W8QkbfIyyIbxlXvcxyWHHvno1Wg0Ej5eiJY5hBb8ExttoIOJJk7V2dZE6prP7iby5q2aQ0Lg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -3056,7 +2966,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", @@ -3092,7 +3001,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -3112,7 +3020,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.28.6.tgz", "integrity": "sha512-pgcbbEl/dWQYb6L6Yew6F94rdwygfuv+vJ/tXfwIOYAfPB6TNWpXUMEtEq3YuTeHRdvMIhvz13bkT9CNaS+wqA==", - "dev": true, "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", @@ -3858,23 +3765,6 @@ "ms": "^2.1.1" } }, - "node_modules/@deck.gl-community/layers": { - "version": "9.2.8", - "resolved": "https://registry.npmjs.org/@deck.gl-community/layers/-/layers-9.2.8.tgz", - "integrity": "sha512-R2EJy5CgS7fByDBxcz88Ci017jqXjj6OpznhS5eGfzhVhutk+paH9mHJFDvwQCLtqI0Ko90o34nBFO17bxqEKw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@deck.gl/core": "~9.2.8", - "@deck.gl/layers": "~9.2.8", - "@deck.gl/mesh-layers": "~9.2.8", - "@luma.gl/constants": "~9.2.6", - "@luma.gl/core": "~9.2.6", - "@luma.gl/engine": "~9.2.6", - "@luma.gl/shadertools": "~9.2.6", - "@math.gl/core": "^4.0.0" - } - }, "node_modules/@deck.gl/aggregation-layers": { "version": "9.2.5", "resolved": "https://registry.npmjs.org/@deck.gl/aggregation-layers/-/aggregation-layers-9.2.5.tgz", @@ -4039,7 +3929,6 @@ "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -5100,7 +4989,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz", "integrity": "sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==", - "dev": true, "license": "MIT" }, "node_modules/@fastify/ajv-compiler": { @@ -5253,7 +5141,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -5263,7 +5151,7 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/ansi": "^1.0.2", @@ -5288,7 +5176,7 @@ "version": "5.1.21", "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/core": "^10.3.2", @@ -5310,7 +5198,7 @@ "version": "10.3.2", "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/ansi": "^1.0.2", @@ -5338,7 +5226,7 @@ "version": "4.2.23", "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/core": "^10.3.2", @@ -5361,7 +5249,7 @@ "version": "4.0.23", "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/core": "^10.3.2", @@ -5384,7 +5272,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "chardet": "^2.1.1", @@ -5406,7 +5294,7 @@ "version": "1.0.15", "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -5416,7 +5304,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/core": "^10.3.2", @@ -5438,7 +5326,7 @@ "version": "3.0.23", "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/core": "^10.3.2", @@ -5460,7 +5348,7 @@ "version": "4.0.23", "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/ansi": "^1.0.2", @@ -5508,7 +5396,7 @@ "version": "4.1.11", "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/core": "^10.3.2", @@ -5531,7 +5419,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/core": "^10.3.2", @@ -5555,7 +5443,7 @@ "version": "4.4.2", "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/ansi": "^1.0.2", @@ -5580,7 +5468,7 @@ "version": "3.0.10", "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -6726,7 +6614,6 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -7286,23 +7173,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@lerna/create/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@lerna/create/node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -8043,7 +7913,6 @@ "integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==", "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.4.4", "@material-ui/styles": "^4.11.5", @@ -8105,7 +7974,6 @@ "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.4.4", "@emotion/hash": "^0.8.0", @@ -8146,22 +8014,19 @@ "version": "0.8.0", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@material-ui/styles/node_modules/csstype": { "version": "2.6.21", "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@material-ui/system": { "version": "4.12.2", "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.4.4", "@material-ui/utils": "^4.11.3", @@ -8190,15 +8055,13 @@ "version": "2.6.21", "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@material-ui/types": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "*" }, @@ -8213,7 +8076,6 @@ "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.4.4", "prop-types": "^15.7.2", @@ -8349,7 +8211,6 @@ "version": "3.0.9", "resolved": "https://registry.npmjs.org/@ndelangen/get-tarball/-/get-tarball-3.0.9.tgz", "integrity": "sha512-9JKTEik4vq+yGosHYhZ1tiH/3WpUS0Nh0kej4Agndhox8pAdWhEx5knFVRcb/ya9knCRCs1rPxNrSXTDdfVqpA==", - "dev": true, "license": "MIT", "dependencies": { "gunzip-maybe": "^1.4.2", @@ -8361,14 +8222,12 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, "license": "ISC" }, "node_modules/@ndelangen/get-tarball/node_modules/tar-fs": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", - "dev": true, "license": "MIT", "dependencies": { "chownr": "^1.1.1", @@ -11600,7 +11459,6 @@ "version": "8.1.11", "resolved": "https://registry.npmjs.org/@storybook/builder-manager/-/builder-manager-8.1.11.tgz", "integrity": "sha512-U7bmed4Ayg+OlJ8HPmLeGxLTHzDY7rxmxM4aAs4YL01fufYfBcjkIP9kFhJm+GJOvGm+YJEUAPe5mbM1P/bn0Q==", - "dev": true, "license": "MIT", "dependencies": { "@fal-works/esbuild-plugin-global-externals": "^2.1.2", @@ -11931,7 +11789,6 @@ "version": "8.1.11", "resolved": "https://registry.npmjs.org/@storybook/cli/-/cli-8.1.11.tgz", "integrity": "sha512-4U48w9C7mVEKrykcPcfHwJkRyCqJ28XipbElACbjIIkQEqaHaOVtP3GeKIrgkoOXe/HK3O4zKWRP2SqlVS0r4A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.24.4", @@ -11984,7 +11841,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -11997,7 +11853,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -12014,7 +11869,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12024,7 +11878,6 @@ "version": "14.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", - "dev": true, "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^2.1.0", @@ -12045,14 +11898,12 @@ "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, "license": "ISC" }, "node_modules/@storybook/cli/node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -12062,7 +11913,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -12075,7 +11925,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -12084,28 +11933,10 @@ "node": ">=8" } }, - "node_modules/@storybook/cli/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@storybook/cli/node_modules/normalize-package-data": { "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==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", @@ -12118,7 +11949,6 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver" @@ -12128,7 +11958,6 @@ "version": "5.4.1", "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, "license": "MIT", "dependencies": { "bl": "^4.1.0", @@ -12152,7 +11981,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -12168,7 +11996,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -12181,7 +12008,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -12194,7 +12020,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, "license": "MIT", "dependencies": { "@types/normalize-package-data": "^2.4.0", @@ -12210,7 +12035,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, "license": "MIT", "dependencies": { "find-up": "^4.1.0", @@ -12228,7 +12052,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -12242,7 +12065,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" @@ -12252,7 +12074,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", - "dev": true, "license": "MIT", "engines": { "node": ">=14.16" @@ -12265,7 +12086,6 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" @@ -12275,7 +12095,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -12301,7 +12120,6 @@ "version": "8.1.11", "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-8.1.11.tgz", "integrity": "sha512-/LCozjH1IQ1TOs9UQV59BE0X6UZ9q+C0NEUz7qmJZPrwAii3FkW4l7D/fwxblpMExaoxv0oE8NQfUz49U/5Ymg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.24.4", @@ -12329,7 +12147,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -12342,7 +12159,6 @@ "version": "14.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", - "dev": true, "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^2.1.0", @@ -12363,7 +12179,6 @@ "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -12373,7 +12188,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -12386,7 +12200,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", - "dev": true, "license": "MIT", "engines": { "node": ">=14.16" @@ -12399,7 +12212,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -12434,38 +12246,6 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" } }, - "node_modules/@storybook/core": { - "version": "8.6.15", - "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.6.15.tgz", - "integrity": "sha512-VFpKcphNurJpSC4fpUfKL3GTXVoL53oytghGR30QIw5jKWwaT50HVbTyb41BLOUuZjmMhUQA8weiQEew6RX0gw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@storybook/theming": "8.6.15", - "better-opn": "^3.0.2", - "browser-assert": "^1.2.1", - "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0", - "esbuild-register": "^3.5.0", - "jsdoc-type-pratt-parser": "^4.0.0", - "process": "^0.11.10", - "recast": "^0.23.5", - "semver": "^7.6.2", - "util": "^0.12.5", - "ws": "^8.2.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "prettier": "^2 || ^3" - }, - "peerDependenciesMeta": { - "prettier": { - "optional": true - } - } - }, "node_modules/@storybook/core-common": { "version": "8.1.11", "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-8.1.11.tgz", @@ -12674,7 +12454,6 @@ "version": "8.1.11", "resolved": "https://registry.npmjs.org/@storybook/core-server/-/core-server-8.1.11.tgz", "integrity": "sha512-L6dzQTmR0np/kagNONvvlm6lSvF1FNc9js3vxsEEPnEypLbhx8bDZaHmuhmBpYUzKyUMpRVQTE/WgjHLuBBuxA==", - "dev": true, "license": "MIT", "dependencies": { "@aw-web-design/x-default-browser": "1.4.126", @@ -12732,7 +12511,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -12745,7 +12523,6 @@ "version": "18.19.130", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -12755,7 +12532,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -12772,7 +12548,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -12786,7 +12561,6 @@ "version": "14.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", - "dev": true, "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^2.1.0", @@ -12807,14 +12581,12 @@ "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, "license": "ISC" }, "node_modules/@storybook/core-server/node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -12824,7 +12596,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -12837,7 +12608,6 @@ "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==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", @@ -12850,7 +12620,6 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver" @@ -12860,7 +12629,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -12876,7 +12644,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -12889,7 +12656,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -12902,7 +12668,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, "license": "MIT", "dependencies": { "@types/normalize-package-data": "^2.4.0", @@ -12918,7 +12683,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, "license": "MIT", "dependencies": { "find-up": "^4.1.0", @@ -12936,7 +12700,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" @@ -12946,7 +12709,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", - "dev": true, "license": "MIT", "engines": { "node": ">=14.16" @@ -12959,7 +12721,6 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" @@ -12969,14 +12730,12 @@ "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true, "license": "MIT" }, "node_modules/@storybook/core-server/node_modules/unicorn-magic": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -13020,47 +12779,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@storybook/core/node_modules/@storybook/theming": { - "version": "8.6.15", - "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.6.15.tgz", - "integrity": "sha512-dAbL0XOekyT6XsF49R6Etj3WxQ/LpdJDIswUUeHgVJ6/yd2opZOGbPxnwA3zlmAh1c0tvpPyhSDXxSG79u8e4Q==", - "license": "MIT", - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" - } - }, - "node_modules/@storybook/core/node_modules/storybook": { - "version": "8.6.15", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.6.15.tgz", - "integrity": "sha512-Ob7DMlwWx8s7dMvcQ3xPc02TvUeralb+xX3oaPRk9wY9Hc6M1IBC/7cEoITkSmRS2v38DHubC+mtEKNc1u2gQg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@storybook/core": "8.6.15" - }, - "bin": { - "getstorybook": "bin/index.cjs", - "sb": "bin/index.cjs", - "storybook": "bin/index.cjs" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "prettier": "^2 || ^3" - }, - "peerDependenciesMeta": { - "prettier": { - "optional": true - } - } - }, "node_modules/@storybook/csf": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.13.tgz", @@ -13110,7 +12828,6 @@ "version": "3.1.0-next.0", "resolved": "https://registry.npmjs.org/@storybook/docs-mdx/-/docs-mdx-3.1.0-next.0.tgz", "integrity": "sha512-t4syFIeSyufieNovZbLruPt2DmRKpbwL4fERCZ1MifWDRIORCKLc4NCEHy+IqvIqd71/SJV2k4B51nF7vlJfmQ==", - "dev": true, "license": "MIT" }, "node_modules/@storybook/docs-tools": { @@ -13156,7 +12873,6 @@ "version": "8.1.11", "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-8.1.11.tgz", "integrity": "sha512-e02y9dmxowo7cTKYm9am7UO6NOHoHy6Xi7xZf/UA932qLwFZUtk5pnwIEFaZWI3OQsRUCGhP+FL5zizU7uVZeg==", - "dev": true, "license": "MIT", "funding": { "type": "opencollective", @@ -13569,7 +13285,6 @@ "version": "8.1.11", "resolved": "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-8.1.11.tgz", "integrity": "sha512-Jqvm7HcZismKzPuebhyLECO6KjGiSk4ycbca1WUM/TUvifxCXqgoUPlHHQEEfaRdHS63/MSqtMNjLsQRLC/vNQ==", - "dev": true, "license": "MIT", "dependencies": { "@storybook/client-logger": "8.1.11", @@ -13590,7 +13305,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -13607,14 +13321,12 @@ "version": "5.0.6", "resolved": "https://registry.npmjs.org/fetch-retry/-/fetch-retry-5.0.6.tgz", "integrity": "sha512-3yurQZ2hD9VISAhJJP9bpYFNQrHHBXE2JxxjY5aLEcDi46RmAzJE2OC9FAde0yis5ElW0jTTzs0zfg/Cca4XqQ==", - "dev": true, "license": "MIT" }, "node_modules/@storybook/telemetry/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -13628,14 +13340,12 @@ "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, "license": "ISC" }, "node_modules/@storybook/telemetry/node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -13648,7 +13358,6 @@ "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==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", @@ -13661,7 +13370,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -13677,7 +13385,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -13690,7 +13397,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, "license": "MIT", "dependencies": { "@types/normalize-package-data": "^2.4.0", @@ -13706,7 +13412,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, "license": "MIT", "dependencies": { "find-up": "^4.1.0", @@ -13724,7 +13429,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" @@ -13734,7 +13438,6 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver" @@ -13744,7 +13447,6 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" @@ -16244,7 +15946,6 @@ "version": "6.0.6", "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.6.tgz", "integrity": "sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -16382,14 +16083,12 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/detect-port/-/detect-port-1.3.5.tgz", "integrity": "sha512-Rf3/lB9WkDfIL9eEKaSYKc+1L/rNVYBjThk22JTqQw0YozXarX8YljFAz+HCoC6h4B4KwCMsBPZHaFezwT4BNA==", - "dev": true, "license": "MIT" }, "node_modules/@types/diff": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.2.3.tgz", "integrity": "sha512-K0Oqlrq3kQMaO2RhfrNQX5trmt+XLyom88zS0u84nnIcLvFnRUMRRHmrGny5GSM+kNO9IZLARsdQHDzkhAgmrQ==", - "dev": true, "license": "MIT" }, "node_modules/@types/doctrine": { @@ -16451,13 +16150,6 @@ "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "license": "MIT" }, - "node_modules/@types/expect": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz", - "integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==", - "license": "MIT", - "peer": true - }, "node_modules/@types/express": { "version": "4.17.25", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", @@ -16896,7 +16588,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", "integrity": "sha512-nj39q0wAIdhwn7DGUyT9irmsKK1tV0bd5WFEhgpqNTMFZ8cE+jieuTphCW0tfdm47S2zVT5mr09B28b1chmQMA==", - "dev": true, "license": "MIT" }, "node_modules/@types/prismjs": { @@ -17152,7 +16843,6 @@ "version": "7.7.1", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", - "dev": true, "license": "MIT" }, "node_modules/@types/send": { @@ -17340,17 +17030,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/vinyl": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.12.tgz", - "integrity": "sha512-Sr2fYMBUVGYq8kj3UthXFAu5UN6ZW+rYr4NACjZQJvHvj+c8lYv0CahmZ2P/r7iUkN44gGUBwqxZkrKXYPb7cw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/expect": "^1.20.4", - "@types/node": "*" - } - }, "node_modules/@types/webpack": { "version": "4.41.40", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.40.tgz", @@ -18817,7 +18496,6 @@ "version": "3.0.0-rc.15", "resolved": "https://registry.npmjs.org/@yarnpkg/esbuild-plugin-pnp/-/esbuild-plugin-pnp-3.0.0-rc.15.tgz", "integrity": "sha512-kYzDJO5CA9sy+on/s2aIW0411AklfCi8Ck/4QDivOqsMKpStZA2SsR+X27VTggGwpStWaLrjJcDcdDMowtG8MA==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "tslib": "^2.4.0" @@ -18888,235 +18566,6 @@ "node": ">=18.12.0" } }, - "node_modules/@yeoman/adapter": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@yeoman/adapter/-/adapter-2.1.1.tgz", - "integrity": "sha512-GJqZ/e+IkgAIaUUqBNngR2Y53eVCiJeMrqx8cLATDauEB6/SdEUIGeyRjaWuXdg+kAJHreFtNdBUDmfHO1lc0w==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@inquirer/core": "^10.0.0", - "chalk": "^5.2.0", - "inquirer": "^12.0.0", - "log-symbols": "^7.0.0", - "ora": "^8.1.0", - "p-queue": "^8.0.1", - "text-table": "^0.2.0" - }, - "engines": { - "node": ">=18.12.0" - } - }, - "node_modules/@yeoman/adapter/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "devOptional": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@yeoman/adapter/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "devOptional": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@yeoman/adapter/node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@yeoman/adapter/node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "devOptional": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@yeoman/adapter/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "devOptional": true, - "license": "MIT", - "peer": true - }, - "node_modules/@yeoman/adapter/node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "devOptional": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@yeoman/adapter/node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@yeoman/adapter/node_modules/ora": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", - "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "chalk": "^5.3.0", - "cli-cursor": "^5.0.0", - "cli-spinners": "^2.9.2", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.0.0", - "log-symbols": "^6.0.0", - "stdin-discarder": "^0.2.2", - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@yeoman/adapter/node_modules/ora/node_modules/log-symbols": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", - "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "chalk": "^5.3.0", - "is-unicode-supported": "^1.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@yeoman/adapter/node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "devOptional": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@yeoman/adapter/node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@yeoman/adapter/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@yeoman/adapter/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/@yeoman/namespace": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@yeoman/namespace/-/namespace-1.0.1.tgz", @@ -19126,33 +18575,6 @@ "node": "^16.13.0 || >=18.12.0" } }, - "node_modules/@yeoman/types": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@yeoman/types/-/types-1.9.1.tgz", - "integrity": "sha512-5BMdA/zMzLv/ahnL1ktaV46nSXorb4sU4kQPQKDhIcK8ERbx9TAbGAE+XAlCXKioNIiOrihYj6gW1d/GEfU9Zw==", - "license": "MIT", - "peer": true, - "engines": { - "node": "^16.13.0 || >=18.12.0" - }, - "peerDependencies": { - "@types/node": ">=16.18.26", - "@yeoman/adapter": "^1.6.0 || ^2.0.0-beta.0 || ^3.0.0 || ^4.0.0", - "mem-fs": "^3.0.0 || ^4.0.0-beta.1", - "mem-fs-editor": "^10.0.2 || >=10.0.2" - }, - "peerDependenciesMeta": { - "@yeoman/adapter": { - "optional": true - }, - "mem-fs": { - "optional": true - }, - "mem-fs-editor": { - "optional": true - } - } - }, "node_modules/@zkochan/js-yaml": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz", @@ -19224,7 +18646,6 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, "license": "MIT", "dependencies": { "mime-types": "~2.1.34", @@ -19318,12 +18739,20 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" } }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/ag-charts-types": { "version": "12.0.2", "resolved": "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-12.0.2.tgz", @@ -19730,7 +19159,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, "license": "MIT" }, "node_modules/array-ify": { @@ -20135,7 +19563,6 @@ "version": "7.0.0-bridge.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", - "dev": true, "license": "MIT", "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -20318,7 +19745,6 @@ "version": "0.4.14", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.27.7", @@ -20333,7 +19759,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -20343,7 +19768,6 @@ "version": "0.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", @@ -20357,7 +19781,6 @@ "version": "0.6.5", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" @@ -20576,7 +19999,6 @@ "version": "2.9.14", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz", "integrity": "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==", - "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -20633,7 +20055,6 @@ "version": "1.6.52", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "dev": true, "license": "Unlicense", "engines": { "node": ">=0.6" @@ -20719,7 +20140,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, "license": "MIT", "dependencies": { "buffer": "^5.5.0", @@ -20731,7 +20151,6 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -20777,7 +20196,6 @@ "version": "1.20.4", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", - "dev": true, "license": "MIT", "dependencies": { "bytes": "~3.1.2", @@ -20802,7 +20220,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -20812,7 +20229,6 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -20825,7 +20241,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/bonjour-service": { @@ -20905,7 +20320,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", - "dev": true, "license": "MIT", "dependencies": { "big-integer": "^1.6.44" @@ -20975,7 +20389,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", "integrity": "sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==", - "dev": true, "license": "MIT", "dependencies": { "pako": "~0.2.0" @@ -20985,14 +20398,12 @@ "version": "0.2.9", "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", - "dev": true, "license": "MIT" }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -21058,7 +20469,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "funding": [ { "type": "github", @@ -21149,7 +20559,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -21488,7 +20897,6 @@ "version": "1.0.30001764", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz", "integrity": "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==", - "dev": true, "funding": [ { "type": "opencollective", @@ -21566,6 +20974,19 @@ "integrity": "sha512-4GMUzkcXHZ0HMZ3gZdBrv8pQs1/zkJh2Q9rQOF8NJZHanM359y3XOSdeqmDBPfxQKYQpJt58R3dUpofrIXJ2mg==", "license": "BSD-3-Clause" }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/chainsaw": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", @@ -21646,7 +21067,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/charenc": { @@ -21737,7 +21158,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -21810,7 +21230,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", - "dev": true, "license": "MIT", "dependencies": { "consola": "^3.2.3" @@ -21878,7 +21297,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" @@ -22004,7 +21422,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -22017,7 +21434,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", - "dev": true, "license": "MIT", "dependencies": { "string-width": "^4.2.0" @@ -22051,7 +21467,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "devOptional": true, + "dev": true, "license": "ISC", "engines": { "node": ">= 12" @@ -22113,7 +21529,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", @@ -22142,7 +21557,6 @@ "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -22168,6 +21582,15 @@ "node": ">= 0.12.0" } }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/collect-v8-coverage": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", @@ -22244,7 +21667,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, "license": "MIT", "optional": true, "engines": { @@ -22305,7 +21727,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -22349,7 +21770,6 @@ "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" @@ -22362,7 +21782,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", - "dev": true, "license": "MIT", "dependencies": { "bytes": "3.1.2", @@ -22381,7 +21800,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -22391,14 +21809,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/compression/node_modules/negotiator": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -22472,7 +21888,6 @@ "version": "0.1.8", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true, "license": "MIT" }, "node_modules/config-chain": { @@ -22512,7 +21927,6 @@ "version": "3.4.2", "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", - "dev": true, "license": "MIT", "engines": { "node": "^14.18.0 || >=16.10.0" @@ -22536,7 +21950,6 @@ "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -22549,7 +21962,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -23628,14 +23040,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, "license": "MIT" }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -23645,7 +23055,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", - "dev": true, "license": "MIT" }, "node_modules/copy-to-clipboard": { @@ -23722,7 +23131,6 @@ "version": "3.47.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", - "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.0" @@ -23797,6 +23205,18 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -24018,7 +23438,6 @@ "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.8.3", "is-in-browser": "^1.0.2" @@ -24217,9 +23636,9 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "15.8.2", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.8.2.tgz", - "integrity": "sha512-KGpuiE8o9l9eyVLPkig574t8zOXkEDKzI0a+RQwy4cfXzpaLipvTOv0t+QEEkLiw/8HbgMNZ0fbPKakJAB3USA==", + "version": "15.12.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.12.0.tgz", + "integrity": "sha512-B2BRcudLfA4NZZP5QpA45J70bu1heCH59V1yKRLHAtiC49r7RV03X5ifUh7Nfbk8QNg93RAsc6oAmodm/+j0pA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -24253,7 +23672,7 @@ "hasha": "5.2.2", "is-installed-globally": "~0.4.0", "listr2": "^3.8.3", - "lodash": "^4.17.21", + "lodash": "^4.17.23", "log-symbols": "^4.0.0", "minimist": "^1.2.8", "ospath": "^1.2.2", @@ -24262,9 +23681,10 @@ "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", "supports-color": "^8.1.1", - "systeminformation": "^5.27.14", + "systeminformation": "^5.31.1", "tmp": "~0.2.4", "tree-kill": "1.2.2", + "tslib": "1.14.1", "untildify": "^4.0.0", "yauzl": "^2.10.0" }, @@ -24385,37 +23805,13 @@ "node": ">=8.12.0" } }, - "node_modules/cypress/node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cypress/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "node_modules/cypress/node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "peer": true }, "node_modules/cypress/node_modules/signal-exit": { "version": "3.0.7", @@ -24442,6 +23838,14 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/cypress/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD", + "peer": true + }, "node_modules/d3": { "version": "3.5.17", "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", @@ -25089,7 +24493,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", - "dev": true, "license": "MIT", "dependencies": { "bplist-parser": "^0.2.0", @@ -25136,7 +24539,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, "license": "MIT", "dependencies": { "clone": "^1.0.2" @@ -25149,7 +24551,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8" @@ -25212,7 +24613,6 @@ "version": "6.1.4", "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "dev": true, "license": "MIT" }, "node_modules/degenerator": { @@ -25253,7 +24653,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -25279,7 +24678,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8", @@ -25326,7 +24724,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/detect-package-manager/-/detect-package-manager-2.0.1.tgz", "integrity": "sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==", - "dev": true, "license": "MIT", "dependencies": { "execa": "^5.1.1" @@ -25339,7 +24736,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", - "dev": true, "license": "MIT", "dependencies": { "address": "^1.0.1", @@ -25357,7 +24753,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -25367,7 +24762,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/devlop": { @@ -25758,7 +25152,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, "license": "MIT" }, "node_modules/ejs": { @@ -25780,7 +25173,6 @@ "version": "1.5.267", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", - "dev": true, "license": "ISC" }, "node_modules/email-addresses": { @@ -25941,7 +25333,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -26222,7 +25613,6 @@ "version": "7.13.0", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", - "dev": true, "license": "MIT", "bin": { "envinfo": "dist/cli.js" @@ -26514,7 +25904,6 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/esbuild-plugin-alias/-/esbuild-plugin-alias-0.2.1.tgz", "integrity": "sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ==", - "dev": true, "license": "MIT" }, "node_modules/esbuild-register": { @@ -27985,7 +27374,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -28204,7 +27592,6 @@ "version": "4.22.1", "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", - "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", @@ -28251,7 +27638,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -28261,7 +27647,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/extend": { @@ -28835,7 +28220,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", - "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", @@ -28854,7 +28238,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -28864,14 +28247,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/find-cache-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, "license": "MIT", "dependencies": { "commondir": "^1.0.1", @@ -28886,7 +28267,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^3.0.0" @@ -28899,7 +28279,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^3.0.0", @@ -28913,7 +28292,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -28929,7 +28307,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.0.0" @@ -28942,7 +28319,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -28952,7 +28328,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, "license": "MIT", "dependencies": { "find-up": "^3.0.0" @@ -29068,19 +28443,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/first-chunk-stream": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-5.0.0.tgz", - "integrity": "sha512-WdHo4ejd2cG2Dl+sLkW79SctU7mUQDfr4s1i26ffOZRs5mgv+BRttIM9gwcq0rDbemo0KlpVPaa3LBVLqPXzcQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -29115,7 +28477,6 @@ "version": "0.296.1", "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.296.1.tgz", "integrity": "sha512-dASEzkw6jlgYx1poIqbf8f21OiyD5f0ebEbvwZVohEixE7agpGb+HbAL35BrzAUyb390nfRfFOsG+alNx1Sqww==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -29392,17 +28753,24 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -29454,7 +28822,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, "license": "MIT" }, "node_modules/fs-extra": { @@ -29704,7 +29071,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -30247,20 +29613,6 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", - "devOptional": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -30298,7 +29650,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/get-npm-tarball-url/-/get-npm-tarball-url-2.1.0.tgz", "integrity": "sha512-ro+DiMu5DXgRBabqXupW38h7WPZ9+Ad8UjwhvsmmN8w1sU7ab0nzAXvVZ4kqYg57OrqomRtJvepX5/xvFKNtjA==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.17" @@ -30682,7 +30033,6 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.5.tgz", "integrity": "sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug==", - "dev": true, "license": "MIT", "dependencies": { "citty": "^0.1.6", @@ -31366,7 +30716,6 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true, "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/brace-expansion": { @@ -31660,7 +31009,6 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz", "integrity": "sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==", - "dev": true, "license": "MIT", "dependencies": { "browserify-zlib": "^0.1.4", @@ -32593,7 +31941,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "dev": true, "license": "MIT", "dependencies": { "depd": "~2.0.0", @@ -32772,8 +32119,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/i18next": { "version": "23.16.8", @@ -32802,7 +32148,7 @@ "version": "0.7.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -33138,65 +32484,6 @@ "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", "license": "MIT" }, - "node_modules/inquirer": { - "version": "12.11.1", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.11.1.tgz", - "integrity": "sha512-9VF7mrY+3OmsAfjH3yKz/pLbJ5z22E23hENKw3/LNSaA/sAt3v49bDRY+Ygct1xwuKT+U+cBfTzjCPySna69Qw==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/core": "^10.3.2", - "@inquirer/prompts": "^7.10.1", - "@inquirer/type": "^3.0.10", - "mute-stream": "^2.0.0", - "run-async": "^4.0.6", - "rxjs": "^7.8.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/inquirer/node_modules/@inquirer/prompts": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", - "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@inquirer/checkbox": "^4.3.2", - "@inquirer/confirm": "^5.1.21", - "@inquirer/editor": "^4.2.23", - "@inquirer/expand": "^4.0.23", - "@inquirer/input": "^4.3.1", - "@inquirer/number": "^3.0.23", - "@inquirer/password": "^4.0.23", - "@inquirer/rawlist": "^4.1.11", - "@inquirer/search": "^3.2.2", - "@inquirer/select": "^4.4.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -33291,7 +32578,6 @@ "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==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.10" @@ -33568,7 +32854,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-deflate/-/is-deflate-1.0.0.tgz", "integrity": "sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==", - "dev": true, "license": "MIT" }, "node_modules/is-docker": { @@ -33670,7 +32955,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz", "integrity": "sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -33690,8 +32974,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/is-inside-container": { "version": "1.0.0", @@ -33750,7 +33033,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -33885,7 +33167,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, "license": "MIT", "dependencies": { "isobject": "^3.0.1" @@ -34055,13 +33336,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", - "license": "MIT", - "peer": true - }, "node_modules/is-weakmap": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", @@ -34162,7 +33436,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -34234,9 +33507,9 @@ } }, "node_modules/istanbul-lib-processinfo": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", - "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-3.0.0.tgz", + "integrity": "sha512-P7nLXRRlo7Sqinty6lNa7+4o9jBUYGpqtejqCOZKfgXlRoxY/QArflcB86YO500Ahj4pDJEG34JjMRbQgePLnQ==", "dev": true, "license": "ISC", "peer": true, @@ -34245,11 +33518,83 @@ "cross-spawn": "^7.0.3", "istanbul-lib-coverage": "^3.2.0", "p-map": "^3.0.0", - "rimraf": "^3.0.0", + "rimraf": "^6.1.3", "uuid": "^8.3.2" }, "engines": { - "node": ">=8" + "node": "20 || >=22" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/lru-cache": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/istanbul-lib-processinfo/node_modules/p-map": { @@ -34266,6 +33611,45 @@ "node": ">=8" } }, + "node_modules/istanbul-lib-processinfo/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/rimraf": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", + "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "glob": "^13.0.3", + "package-json-from-dist": "^1.0.1" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/istanbul-lib-processinfo/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -36576,7 +35960,6 @@ "version": "0.15.2", "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.15.2.tgz", "integrity": "sha512-FquR7Okgmc4Sd0aEDwqho3rEiKR3BdvuG9jfdHjLJ6JQoWSMpavug3AoIfnfWhxFlf+5pzQh8qjqz0DWFrNQzA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.23.0", @@ -36616,7 +35999,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -36633,14 +36015,12 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, "license": "ISC" }, "node_modules/jscodeshift/node_modules/write-file-atomic": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, "license": "ISC", "dependencies": { "graceful-fs": "^4.1.11", @@ -36648,16 +36028,6 @@ "signal-exit": "^3.0.2" } }, - "node_modules/jsdoc-type-pratt-parser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.8.0.tgz", - "integrity": "sha512-iZ8Bdb84lWRuGHamRXFyML07r21pcwBrLkHEuHgEY5UbCouBwv7ECknDRKzsQIXMiqpPymqtIf8TC/shYKB5rw==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/jsdom": { "version": "26.1.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", @@ -36994,7 +36364,6 @@ "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.3.1", "csstype": "^3.0.2", @@ -37011,7 +36380,6 @@ "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.3.1", "hyphenate-style-name": "^1.0.3", @@ -37023,7 +36391,6 @@ "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.3.1", "jss": "10.10.0" @@ -37034,7 +36401,6 @@ "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.3.1", "jss": "10.10.0" @@ -37045,7 +36411,6 @@ "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.3.1", "jss": "10.10.0", @@ -37057,7 +36422,6 @@ "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.3.1", "jss": "10.10.0" @@ -37068,7 +36432,6 @@ "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.3.1", "jss": "10.10.0", @@ -37080,7 +36443,6 @@ "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.3.1", "css-vendor": "^2.0.8", @@ -37185,7 +36547,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -37195,7 +36556,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -37721,23 +37081,6 @@ "node": ">=8" } }, - "node_modules/lerna/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lerna/node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -37987,7 +37330,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -38241,7 +37583,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true, "license": "MIT" }, "node_modules/lodash.escaperegexp": { @@ -38368,18 +37709,44 @@ "license": "MIT" }, "node_modules/log-symbols": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", - "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", - "devOptional": true, + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "license": "MIT", - "peer": true, "dependencies": { - "is-unicode-supported": "^2.0.0", - "yoctocolors": "^2.1.1" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "engines": { - "node": ">=18" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "license": "MIT", + "engines": { + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -38514,7 +37881,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -38600,7 +37966,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, "license": "MIT", "dependencies": { "pify": "^4.0.1", @@ -38614,7 +37979,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -38624,7 +37988,6 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver" @@ -39285,28 +38648,11 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, - "node_modules/mem-fs": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/mem-fs/-/mem-fs-4.1.3.tgz", - "integrity": "sha512-+2zSUVKcDWgcF90mPPwyH4J814uRI1PJcVt2RZ4/E8VggPEiIEL7ikMTlPR91P2ZySkyPgD0YGrccwo55SZvnw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": ">=18", - "@types/vinyl": "^2.0.12", - "vinyl": "^3.0.0", - "vinyl-file": "^5.0.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/mem-fs-editor": { "version": "11.1.4", "resolved": "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-11.1.4.tgz", @@ -39499,7 +38845,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -39542,7 +38887,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -40149,7 +39493,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -40159,7 +39502,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -40177,20 +39519,6 @@ "node": ">=6" } }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "devOptional": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -40307,10 +39635,10 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -40449,7 +39777,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, "license": "MIT", "dependencies": { "minipass": "^3.0.0", @@ -40463,7 +39790,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -40476,7 +39802,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, "license": "ISC" }, "node_modules/mitt": { @@ -40495,7 +39820,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" @@ -40508,14 +39832,12 @@ "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true, "license": "MIT" }, "node_modules/mlly": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", - "dev": true, "license": "MIT", "dependencies": { "acorn": "^8.15.0", @@ -40528,7 +39850,6 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -40557,16 +39878,6 @@ "node": ">=0.10.0" } }, - "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", - "license": "MIT", - "peer": true, - "engines": { - "node": "*" - } - }, "node_modules/monaco-editor": { "version": "0.49.0", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.49.0.tgz", @@ -40681,7 +39992,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", - "devOptional": true, + "dev": true, "license": "ISC", "engines": { "node": "^18.17.0 || >=20.5.0" @@ -40752,7 +40063,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -40843,7 +40153,6 @@ "version": "0.1.17", "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", - "dev": true, "license": "MIT", "dependencies": { "minimatch": "^3.0.2" @@ -40856,7 +40165,6 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -40867,7 +40175,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -40956,7 +40263,6 @@ "version": "1.6.7", "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", - "dev": true, "license": "MIT" }, "node_modules/node-fetch/node_modules/tr46": { @@ -41085,7 +40391,6 @@ "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true, "license": "MIT" }, "node_modules/nomnom": { @@ -43935,36 +43240,6 @@ "node": ">=8.6" } }, - "node_modules/nx/node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nx/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/nx/node_modules/minimatch": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", @@ -44005,9 +43280,9 @@ } }, "node_modules/nyc": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-17.1.0.tgz", - "integrity": "sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-18.0.0.tgz", + "integrity": "sha512-G5UyHinFkB1BxqGTrmZdB6uIYH0+v7ZnVssuflUDi+J+RhKWyAhRT1RCehBSI6jLFLuUUgFDyLt49mUtdO1XeQ==", "dev": true, "license": "ISC", "peer": true, @@ -44021,11 +43296,11 @@ "find-up": "^4.1.0", "foreground-child": "^3.3.0", "get-package-type": "^0.1.0", - "glob": "^7.1.6", + "glob": "^13.0.6", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-hook": "^3.0.0", "istanbul-lib-instrument": "^6.0.2", - "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-processinfo": "^3.0.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.2", @@ -44034,17 +43309,42 @@ "p-map": "^3.0.0", "process-on-spawn": "^1.0.0", "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", + "rimraf": "^6.1.3", "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", + "spawn-wrap": "^3.0.0", + "test-exclude": "^8.0.0", "yargs": "^15.0.2" }, "bin": { "nyc": "bin/nyc.js" }, "engines": { - "node": ">=18" + "node": "20 || >=22" + } + }, + "node_modules/nyc/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/nyc/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/nyc/node_modules/camelcase": { @@ -44113,6 +43413,25 @@ "node": ">=8" } }, + "node_modules/nyc/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/nyc/node_modules/istanbul-lib-source-maps": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", @@ -44143,6 +43462,17 @@ "node": ">=8" } }, + "node_modules/nyc/node_modules/lru-cache": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/nyc/node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -44160,6 +43490,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/nyc/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/nyc/node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -44205,6 +43552,24 @@ "node": ">=8" } }, + "node_modules/nyc/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/nyc/node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -44219,6 +43584,27 @@ "node": ">=8" } }, + "node_modules/nyc/node_modules/rimraf": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", + "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "glob": "^13.0.3", + "package-json-from-dist": "^1.0.1" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/nyc/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -44249,6 +43635,22 @@ "node": ">=0.10.0" } }, + "node_modules/nyc/node_modules/test-exclude": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz", + "integrity": "sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^13.0.6", + "minimatch": "^10.2.2" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/nyc/node_modules/y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", @@ -44300,7 +43702,6 @@ "version": "0.5.4", "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.5.4.tgz", "integrity": "sha512-X0SNNrZiGU8/e/zAB7sCTtdxWTMSIO73q+xuKgglm2Yvzwlo8UoC5FNySQFCvl84uPaeADkqHUZUkWy4aH4xOA==", - "dev": true, "license": "MIT", "dependencies": { "citty": "^0.1.6", @@ -44321,7 +43722,6 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true, "license": "MIT" }, "node_modules/object-assign": { @@ -44557,7 +43957,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -44570,7 +43969,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -45093,24 +44491,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-queue": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.1.tgz", - "integrity": "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "eventemitter3": "^5.0.1", - "p-timeout": "^6.1.2" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-reduce": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", @@ -45528,7 +44908,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -45617,7 +44996,6 @@ "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "dev": true, "license": "MIT" }, "node_modules/path-type": { @@ -45633,7 +45011,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, "license": "MIT" }, "node_modules/pbf": { @@ -45777,7 +45154,6 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -45925,7 +45301,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "dev": true, "license": "MIT", "dependencies": { "confbox": "^0.1.8", @@ -46009,8 +45384,7 @@ "version": "1.16.1-lts", "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/possible-typed-array-names": { "version": "1.1.0", @@ -46754,7 +46128,6 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", - "devOptional": true, "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" @@ -47067,7 +46440,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, "license": "MIT", "dependencies": { "kleur": "^3.0.3", @@ -47140,7 +46512,6 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -47260,7 +46631,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "dev": true, "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -47271,7 +46641,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, "license": "MIT", "dependencies": { "duplexify": "^3.6.0", @@ -47283,7 +46652,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -47599,7 +46967,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -47609,7 +46976,6 @@ "version": "2.5.3", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", - "dev": true, "license": "MIT", "dependencies": { "bytes": "~3.1.2", @@ -47625,7 +46991,6 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -49851,14 +49216,12 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true, "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.2.2", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", - "dev": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2" @@ -49907,7 +49270,6 @@ "version": "6.4.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", - "dev": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2", @@ -49952,14 +49314,12 @@ "version": "0.8.0", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "dev": true, "license": "MIT" }, "node_modules/regjsparser": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "jsesc": "~3.1.0" @@ -51309,7 +50669,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, "license": "MIT", "dependencies": { "onetime": "^5.1.0", @@ -51323,7 +50682,6 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, "license": "ISC" }, "node_modules/ret": { @@ -51421,17 +50779,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-async": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz", - "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==", - "devOptional": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -51464,7 +50811,7 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" @@ -51577,7 +50924,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "devOptional": true, "license": "MIT" }, "node_modules/sax": { @@ -52030,7 +51376,6 @@ "version": "0.19.2", "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", - "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", @@ -52055,7 +51400,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -52065,14 +51409,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/send/node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, "license": "MIT", "bin": { "mime": "cli.js" @@ -52085,7 +51427,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/serialize-javascript": { @@ -52197,7 +51538,6 @@ "version": "1.16.3", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", - "dev": true, "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", @@ -52279,14 +51619,12 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, "license": "ISC" }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, "license": "MIT", "dependencies": { "kind-of": "^6.0.2" @@ -52707,7 +52045,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, "license": "MIT" }, "node_modules/skin-tone": { @@ -52984,7 +52321,6 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -52995,7 +52331,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -53018,17 +52353,18 @@ "license": "MIT" }, "node_modules/spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-3.0.0.tgz", + "integrity": "sha512-z+s5vv4KzFPJVddGab0xX2n7kQPGMdNUX5l9T8EJqsXdKTWpcxmAqWHpsgHEXoC1taGBCc7b79bi62M5kdbrxQ==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "peer": true, "dependencies": { + "cross-spawn": "^7.0.6", "foreground-child": "^2.0.0", "is-windows": "^1.0.2", "make-dir": "^3.0.0", - "rimraf": "^3.0.0", + "rimraf": "^6.1.3", "signal-exit": "^3.0.2", "which": "^2.0.1" }, @@ -53036,6 +52372,31 @@ "node": ">=8" } }, + "node_modules/spawn-wrap/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/spawn-wrap/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/spawn-wrap/node_modules/foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -53051,6 +52412,36 @@ "node": ">=8.0.0" } }, + "node_modules/spawn-wrap/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/spawn-wrap/node_modules/lru-cache": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/spawn-wrap/node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -53068,6 +52459,62 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/spawn-wrap/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/spawn-wrap/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/spawn-wrap/node_modules/rimraf": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", + "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "glob": "^13.0.3", + "package-json-from-dist": "^1.0.1" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/spawn-wrap/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -53262,8 +52709,19 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" + }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } }, "node_modules/sshpk": { "version": "1.18.0", @@ -53529,26 +52987,11 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/stdin-discarder": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", - "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", - "devOptional": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -53572,7 +53015,6 @@ "version": "8.1.11", "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.1.11.tgz", "integrity": "sha512-3KjIhF8lczXhKKHyHbOqV30dvuRYJSxc0d1as/C8kybuwE7cLaydhWGma7VBv5bTSPv0rDzucx7KcO+achArPg==", - "dev": true, "license": "MIT", "dependencies": { "@storybook/cli": "8.1.11" @@ -53894,39 +53336,6 @@ "node": ">=8" } }, - "node_modules/strip-bom-buf": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-3.0.1.tgz", - "integrity": "sha512-iJaWw2WroigLHzQysdc5WWeUc99p7ea7AEgB6JkY8CMyiO1yTVAA1gIlJJgORElUIR+lcZJkNl1OGChMhvc2Cw==", - "license": "MIT", - "peer": true, - "dependencies": { - "is-utf8": "^0.2.1" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-bom-stream": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-5.0.0.tgz", - "integrity": "sha512-Yo472mU+3smhzqeKlIxClre4s4pwtYZEvDNQvY/sJpnChdaxmKuwU28UVx/v1ORKNMxkmj1GBuvxJQyBk6wYMQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "first-chunk-stream": "^5.0.0", - "strip-bom-buf": "^3.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/strip-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", @@ -54274,9 +53683,9 @@ } }, "node_modules/systeminformation": { - "version": "5.30.3", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.30.3.tgz", - "integrity": "sha512-NgHJUpA+y7j4asLQa9jgBt+Eb2piyQIXQ+YjOyd2K0cHNwbNJ6I06F5afOqOiaCuV/wrEyGrb0olg4aFLlJD+A==", + "version": "5.31.5", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.5.tgz", + "integrity": "sha512-5SyLdip4/3alxD4Kh+63bUQTJmu7YMfYQTC+koZy7X73HgNqZSD2P4wOZQWtUncvPvcEmnfIjCoygN4MRoEejQ==", "dev": true, "license": "MIT", "os": [ @@ -54319,7 +53728,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, "license": "ISC", "dependencies": { "chownr": "^2.0.0", @@ -54379,7 +53787,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, "license": "MIT", "dependencies": { "bl": "^4.0.3", @@ -54396,7 +53803,6 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -54411,7 +53817,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -54424,7 +53829,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -54437,7 +53841,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, "license": "ISC", "engines": { "node": ">=8" @@ -54447,7 +53850,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, "license": "ISC" }, "node_modules/teen_process": { @@ -54490,7 +53892,6 @@ "version": "0.8.4", "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", - "dev": true, "license": "MIT", "dependencies": { "rimraf": "~2.6.2" @@ -54514,7 +53915,6 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -55100,7 +54500,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.6" @@ -56150,7 +55549,6 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, "license": "MIT", "dependencies": { "media-typer": "0.3.0", @@ -56328,7 +55726,6 @@ "version": "1.6.2", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.2.tgz", "integrity": "sha512-heMioaxBcG9+Znsda5Q8sQbWnLJSl98AFDXTO80wELWEzX3hordXsTdxrIfMQoO9IY1MEnoGoPjpoKpMj+Yx0Q==", - "dev": true, "license": "MIT" }, "node_modules/uglify-js": { @@ -56411,7 +55808,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -56430,7 +55826,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", @@ -56444,7 +55839,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -56454,7 +55848,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -56704,7 +56097,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -56783,7 +56175,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -56804,7 +56195,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, "funding": [ { "type": "opencollective", @@ -57008,7 +56398,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4.0" @@ -57162,7 +56551,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -57366,25 +56754,6 @@ "node": ">=10.13.0" } }, - "node_modules/vinyl-file": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-5.0.0.tgz", - "integrity": "sha512-MvkPF/yA1EX7c6p+juVIvp9+Lxp70YUfNKzEWeHMKpUNVSnTZh2coaOqLxI0pmOe2V9nB+OkgFaMDkodaJUyGw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/vinyl": "^2.0.7", - "strip-bom-buf": "^3.0.1", - "strip-bom-stream": "^5.0.0", - "vinyl": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/vlq": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", @@ -57443,7 +56812,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.0.tgz", "integrity": "sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==", - "dev": true, "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", @@ -57467,7 +56835,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, "license": "MIT", "dependencies": { "defaults": "^1.0.3" @@ -58503,6 +57870,24 @@ "integrity": "sha512-1ZUiV1FTwSiSrgWzV9KXJuOF2BVW91KY/mau04BhnmgOdroRQea7Q0s5TVqwGLm0D2tZwObd/tBYXW49sSxp3Q==", "license": "MIT" }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -58522,7 +57907,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -58817,7 +58202,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, "license": "ISC" }, "node_modules/yaml": { @@ -59141,7 +58525,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -60072,33 +59456,6 @@ "url": "https://opencollective.com/webpack" } }, - "packages/superset-ui-demo/node_modules/storybook": { - "version": "8.6.15", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.6.15.tgz", - "integrity": "sha512-Ob7DMlwWx8s7dMvcQ3xPc02TvUeralb+xX3oaPRk9wY9Hc6M1IBC/7cEoITkSmRS2v38DHubC+mtEKNc1u2gQg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@storybook/core": "8.6.15" - }, - "bin": { - "getstorybook": "bin/index.cjs", - "sb": "bin/index.cjs", - "storybook": "bin/index.cjs" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "prettier": "^2 || ^3" - }, - "peerDependenciesMeta": { - "prettier": { - "optional": true - } - } - }, "packages/superset-ui-demo/node_modules/style-loader": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", @@ -60174,6 +59531,9 @@ "@mapbox/geojson-extent": "^1.0.1", "@material-ui/icons": "^4.11.3", "@math.gl/web-mercator": "^4.1.0", + "@turf/boolean-point-in-polygon": "^7.2.0", + "@turf/centroid": "^7.2.0", + "@turf/helpers": "^7.2.0", "@types/d3-array": "^2.0.0", "@types/d3-interpolate": "^3.0.4", "@types/d3-scale-chromatic": "^3.1.0", @@ -60194,6 +59554,7 @@ "underscore": "^1.13.7", "urijs": "^1.19.11", "wellknown": "^0.5.0", + "xlsx": "^0.18.5", "xss": "^1.0.15" }, "devDependencies": { @@ -60289,41 +59650,6 @@ "@luma.gl/engine": "~9.2.6" } }, - "plugins/geoset-map-chart/node_modules/@deck.gl/geo-layers": { - "version": "9.2.11", - "resolved": "https://registry.npmjs.org/@deck.gl/geo-layers/-/geo-layers-9.2.11.tgz", - "integrity": "sha512-Mr3yvKyZMPmQ3ho0hSqcJu1p7a881RqQaq/dRaPs2VP56UAkfk1e10zxXnrZ9/Dmo2MR5PH0j8tkOoGR3zKbfA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@loaders.gl/3d-tiles": "~4.3.4", - "@loaders.gl/gis": "~4.3.4", - "@loaders.gl/loader-utils": "~4.3.4", - "@loaders.gl/mvt": "~4.3.4", - "@loaders.gl/schema": "~4.3.4", - "@loaders.gl/terrain": "~4.3.4", - "@loaders.gl/tiles": "~4.3.4", - "@loaders.gl/wms": "~4.3.4", - "@luma.gl/gltf": "~9.2.6", - "@luma.gl/shadertools": "~9.2.6", - "@math.gl/core": "^4.1.0", - "@math.gl/culling": "^4.1.0", - "@math.gl/web-mercator": "^4.1.0", - "@types/geojson": "^7946.0.8", - "a5-js": "^0.5.0", - "h3-js": "^4.1.0", - "long": "^3.2.0" - }, - "peerDependencies": { - "@deck.gl/core": "~9.2.0", - "@deck.gl/extensions": "~9.2.0", - "@deck.gl/layers": "~9.2.0", - "@deck.gl/mesh-layers": "~9.2.0", - "@loaders.gl/core": "~4.3.4", - "@luma.gl/core": "~9.2.6", - "@luma.gl/engine": "~9.2.6" - } - }, "plugins/geoset-map-chart/node_modules/@turf/boolean-clockwise": { "version": "7.3.4", "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-7.3.4.tgz", @@ -60491,6 +59817,27 @@ "uuid": "dist/bin/uuid" } }, + "plugins/geoset-map-chart/node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "plugins/legacy-plugin-chart-calendar": { "name": "@superset-ui/legacy-plugin-chart-calendar", "version": "0.20.3", @@ -61053,13 +60400,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "plugins/plugin-chart-handlebars/node_modules/currencyformatter.js": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/currencyformatter.js/-/currencyformatter.js-1.0.5.tgz", - "integrity": "sha512-gNhjgPges50sAHOb56BeEOi33w88sED2nSiY0s9niq1S/64IKB8DB1EmJh8wv5PofFXpHWG91yptoDQAj5GI2w==", - "license": "MIT", - "peer": true - }, "plugins/plugin-chart-handlebars/node_modules/expect": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 1a6c2f63b5..aea252781f 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -88,6 +88,7 @@ "@emotion/cache": "^11.4.0", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", + "@material-ui/core": "^4.12.4", "@reduxjs/toolkit": "^1.9.3", "@rjsf/core": "^5.21.1", "@rjsf/utils": "^5.24.3", @@ -151,11 +152,11 @@ "immer": "^10.1.1", "interweave": "^13.1.0", "jquery": "^3.7.1", - "jspdf": "^3.0.1", "js-levenshtein": "^1.1.6", "js-yaml-loader": "^1.2.2", "json-bigint": "^1.0.0", "json-stringify-pretty-compact": "^2.0.0", + "jspdf": "^3.0.1", "lodash": "^4.17.21", "luxon": "^3.5.0", "mapbox-gl": "^3.13.0", @@ -201,6 +202,7 @@ "rison": "^0.1.1", "scroll-into-view-if-needed": "^3.1.0", "simple-zstd": "^1.4.2", + "sprintf-js": "^1.1.3", "stream-browserify": "^3.0.0", "tinycolor2": "^1.4.2", "urijs": "^1.19.8", diff --git a/superset-frontend/plugins/geoset-map-chart/package.json b/superset-frontend/plugins/geoset-map-chart/package.json index f50269e33f..f0d3731cd9 100644 --- a/superset-frontend/plugins/geoset-map-chart/package.json +++ b/superset-frontend/plugins/geoset-map-chart/package.json @@ -26,6 +26,9 @@ "dependencies": { "@ant-design/icons": "^5.6.1", "@deck.gl-community/editable-layers": "^9.2.8", + "@turf/boolean-point-in-polygon": "^7.2.0", + "@turf/centroid": "^7.2.0", + "@turf/helpers": "^7.2.0", "@deck.gl/aggregation-layers": "^9.1.14", "@deck.gl/core": "^9.1.14", "@deck.gl/extensions": "^9.1.14", @@ -54,6 +57,7 @@ "underscore": "^1.13.7", "urijs": "^1.19.11", "wellknown": "^0.5.0", + "xlsx": "^0.18.5", "xss": "^1.0.15" }, "devDependencies": { diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx index 6df5433268..93af9c494d 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx @@ -45,11 +45,12 @@ import { LayerState } from '../types'; import buildGeoSetMapLayerQuery from '../buildQuery'; import transformGeoSetMapLayerProps from '../transformProps'; import MultiLegend from '../components/MultiLegend'; -import type { CategoryEntry, LegendEntry } from '../types'; +import type { CategoryEntry, GeoJsonFeature, LegendEntry } from '../types'; import { useGroupedLegend } from '../utils/hooks'; import MapControls from '../components/MapControls'; -import type { Coordinate } from '../utils/measureDistance'; import { useLassoSelection } from '../hooks/useLassoSelection'; +import { filterMultiLayerFeaturesInLasso } from '../utils/lassoSelection'; +import LassoResultsBar from '../components/LassoResultsBar'; import { CategoryState, MetricLegend, RGBAColor } from '../utils/colors'; import { getGeometryType } from '../utils/dataProcessing'; import { fetchMapboxApiKey, getCachedMapboxApiKey } from '../utils/mapboxApi'; @@ -1017,6 +1018,9 @@ const DeckMulti = (props: DeckMultiProps) => { lassoDrawMode, setLassoDrawMode, selectedLassoLayerIds, + selectedFeatures, + setSelectedFeatures, + clearSelection, handleLassoToggle, handleLassoActivate, handleLassoComplete, @@ -1024,6 +1028,40 @@ const DeckMulti = (props: DeckMultiProps) => { deactivateLasso, } = useLassoSelection({ availableLayers: lassoLayers, + onPolygonComplete: polygon => { + const layerFeatureMap: Record = {}; + sortedLayers.forEach(entry => { + const layerId = String(entry.sliceId); + if (!selectedLassoLayerIds.includes(layerId)) return; + + const allFeatures = + (entry.transformedProps.payload?.data + ?.features as GeoJsonFeature[]) || []; + + // Filter out features whose category is hidden in the legend + const sliceVisibility = categoryVisibility[layerId]; + const dimension = entry.transformedProps.visualConfig?.dimension as + | string + | undefined; + const visibleFeatures = + sliceVisibility && dimension + ? allFeatures.filter(f => { + const raw = + (f as any).categoryName ?? f.properties?.[dimension]; + if (raw == null) return true; + const key = String(raw); + return sliceVisibility[key] !== false; + }) + : allFeatures; + + const name = + (entry.legendEntry.sliceName as string | undefined) || + entry.legendEntry.legendName; + layerFeatureMap[name] = visibleFeatures; + }); + const result = filterMultiLayerFeaturesInLasso(layerFeatureMap, polygon); + setSelectedFeatures(result.features); + }, onActivate: () => { setMeasureState({ startPoint: null, @@ -1188,6 +1226,13 @@ const DeckMulti = (props: DeckMultiProps) => { onLassoDrawModeChange={setLassoDrawMode} position="top-right" /> + {selectedFeatures.length > 0 && ( + + )} {clickedFeature && ( void; +} + +const BarContainer = styled.div` + position: absolute; + bottom: 12px; + left: 50%; + transform: translateX(-50%); + z-index: 20; + pointer-events: auto; +`; + +const BarContent = styled.div( + ({ theme }) => ` + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + background: ${theme.colorBgElevated}; + border: 1px solid ${theme.colorBorderSecondary}; + border-radius: 6px; + box-shadow: 0 2px 8px ${theme.colorText}1F; + white-space: nowrap; +`, +); + +const CountLabel = styled.span( + ({ theme }) => ` + font-size: 13px; + font-weight: 600; + color: ${theme.colorText}; +`, +); + +const IconButton = styled.button( + ({ theme }) => ` + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + padding: 0; + background: transparent; + border: none; + border-radius: 4px; + cursor: pointer; + color: ${theme.colorTextSecondary}; + + &:hover { + background: ${theme.colorBgTextHover}; + color: ${theme.colorText}; + } +`, +); + +const MenuPanel = styled.div( + ({ theme }) => ` + position: absolute; + bottom: calc(100% + 6px); + right: 0; + min-width: 160px; + background: ${theme.colorBgElevated}; + border: 1px solid ${theme.colorBorderSecondary}; + border-radius: 6px; + box-shadow: 0 4px 12px ${theme.colorText}1F; + overflow: hidden; +`, +); + +const MenuItem = styled.button<{ $disabled?: boolean }>( + ({ theme, $disabled }) => ` + display: flex; + align-items: center; + gap: 8px; + width: 100%; + padding: 8px 12px; + background: transparent; + border: none; + cursor: ${$disabled ? 'default' : 'pointer'}; + font-family: inherit; + font-size: 13px; + color: ${$disabled ? theme.colorTextSecondary : theme.colorText}; + opacity: ${$disabled ? 0.5 : 1}; + text-align: left; + white-space: nowrap; + + &:hover { + background: ${$disabled ? 'transparent' : theme.colorBgTextHover}; + } +`, +); + +const KebabIcon = () => ( + + + + + +); + +const CloseIcon = () => ( + + + + +); + +const DownloadIcon = () => ( + + + +); + +const LassoResultsBar = ({ count, features, onClear }: LassoResultsBarProps) => { + const [isMenuOpen, setIsMenuOpen] = useState(false); + const containerRef = useRef(null); + + // Close menu on outside click + useEffect(() => { + if (!isMenuOpen) return undefined; + const handleOutsideClick = (e: MouseEvent) => { + if ( + containerRef.current && + !containerRef.current.contains(e.target as Node) + ) { + setIsMenuOpen(false); + } + }; + document.addEventListener('mousedown', handleOutsideClick); + return () => document.removeEventListener('mousedown', handleOutsideClick); + }, [isMenuOpen]); + + if (count === 0) return null; + + return ( + + + {count} Items Selected + setIsMenuOpen(prev => !prev)} + title="Export options" + > + + + + + + + + {isMenuOpen && ( + + { + exportToCSV(features); + setIsMenuOpen(false); + }} + > + Export to .CSV + + { + exportToExcel(features); + setIsMenuOpen(false); + }} + > + Export to Excel + + + Download as image + + + )} + + ); +}; + +export default memo(LassoResultsBar); diff --git a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts index b48eae5ba9..f6b900db50 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts +++ b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts @@ -20,6 +20,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'; import type { LassoDrawMode } from '../components/LassoOverlay'; import type { Coordinate } from '../utils/measureDistance'; import type { LassoLayer } from '../components/MapControls'; +import type { GeoJsonFeature } from '../types'; export type UseLassoSelectionOptions = { /** Available layers for multi-layer selection. Omit or pass empty for single-layer. */ @@ -35,6 +36,10 @@ export type UseLassoSelectionResult = { lassoDrawMode: LassoDrawMode; setLassoDrawMode: (mode: LassoDrawMode) => void; selectedLassoLayerIds: string[]; + selectedFeatures: GeoJsonFeature[]; + setSelectedFeatures: (features: GeoJsonFeature[]) => void; + lassoPolygon: Coordinate[] | null; + clearSelection: () => void; handleLassoToggle: () => void; handleLassoActivate: () => void; handleLassoComplete: (polygon: Coordinate[]) => void; @@ -58,6 +63,10 @@ export function useLassoSelection( const [selectedLassoLayerIds, setSelectedLassoLayerIds] = useState( [], ); + const [selectedFeatures, setSelectedFeatures] = useState( + [], + ); + const [lassoPolygon, setLassoPolygon] = useState(null); // Auto-select the first layer when available layers load and none are selected. // Serialize IDs as the dependency so the effect only fires when actual layers change. @@ -73,10 +82,17 @@ export function useLassoSelection( setLassoIsActive(false); }, []); - // Toggle lasso off — full reset including layer selections + const clearSelection = useCallback(() => { + setSelectedFeatures([]); + setLassoPolygon(null); + }, []); + + // Toggle lasso off — full reset including layer selections and results const handleLassoToggle = useCallback(() => { setLassoIsActive(false); setSelectedLassoLayerIds([]); + setSelectedFeatures([]); + setLassoPolygon(null); }, []); // Activate lasso drawing and notify parent (e.g. to deactivate ruler) @@ -85,8 +101,9 @@ export function useLassoSelection( setLassoIsActive(true); }, []); - // Forward completed polygon to consumer + // Store completed polygon and forward to consumer const handleLassoComplete = useCallback((polygon: Coordinate[]) => { + setLassoPolygon(polygon); onPolygonCompleteRef.current?.(polygon); }, []); @@ -106,6 +123,8 @@ export function useLassoSelection( const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') { setLassoIsActive(false); + setSelectedFeatures([]); + setLassoPolygon(null); } }; document.addEventListener('keydown', handleKeyDown); @@ -117,6 +136,10 @@ export function useLassoSelection( lassoDrawMode, setLassoDrawMode, selectedLassoLayerIds, + selectedFeatures, + setSelectedFeatures, + lassoPolygon, + clearSelection, handleLassoToggle, handleLassoActivate, handleLassoComplete, diff --git a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx index 689f0c346d..9d1053df94 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx @@ -57,6 +57,8 @@ import { calculateAutozoomViewport, Viewport } from '../../utils/fitViewport'; import { TooltipProps } from '../../components/Tooltip'; import Legend, { SizeLegend } from '../../components/Legend'; import MapControls from '../../components/MapControls'; +import LassoResultsBar from '../../components/LassoResultsBar'; +import { filterFeaturesInLasso } from '../../utils/lassoSelection'; import { GeoJsonFeature, LayerState } from '../../types'; import { useDebouncedValue } from '../../utils/hooks'; import { normalizeRGBA } from '../../utils/colorsFallback'; @@ -952,14 +954,41 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { lassoIsActive, lassoDrawMode, setLassoDrawMode, + selectedFeatures, + setSelectedFeatures, + clearSelection, handleLassoToggle, handleLassoActivate, handleLassoComplete, deactivateLasso, } = useLassoSelection({ onPolygonComplete: polygon => { - // TODO: point-in-polygon query + results bar - console.log('Lasso complete (single layer):', polygon); + const allFeatures = + (payload?.data?.features as GeoJsonFeature[]) || []; + const dimension = propVisualConfig?.dimension as string | undefined; + + // Only include features whose category is visible in the legend + const disabledKeys = new Set( + Object.entries(categories) + .filter(([, cat]) => cat.enabled === false) + .map(([key]) => key), + ); + const visibleFeatures = + disabledKeys.size > 0 && dimension + ? allFeatures.filter(f => { + const raw = + (f as any).categoryName ?? f.properties?.[dimension]; + if (raw == null) return true; + const key = + typeof raw === 'string' + ? raw.trim().toLowerCase() + : String(raw); + return !disabledKeys.has(key); + }) + : allFeatures; + + const selected = filterFeaturesInLasso(visibleFeatures, polygon); + setSelectedFeatures(selected); }, onActivate: () => { setMeasureState({ @@ -1259,6 +1288,13 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { onLassoDrawModeChange={setLassoDrawMode} position="top-right" /> + {selectedFeatures.length > 0 && ( + + )} [] } { + const keySet = new Set(); + features.forEach(f => { + if (f.properties) { + Object.keys(f.properties).forEach(k => keySet.add(k)); + } + }); + + const propHeaders = Array.from(keySet).sort(); + const headers = ['_geometry_type', '_longitude', '_latitude', ...propHeaders]; + + const rows = features.map(f => { + const pt = getRepresentativePoint(f); + const row: Record = { + _geometry_type: f.geometry?.type ?? '', + _longitude: pt?.[0] ?? '', + _latitude: pt?.[1] ?? '', + }; + propHeaders.forEach(key => { + row[key] = f.properties?.[key] ?? ''; + }); + return row; + }); + + return { headers, rows }; +} + +function timestamp(): string { + return new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19); +} + +function triggerDownload(blob: Blob, filename: string) { + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); +} + +function escapeCSV(value: any): string { + const str = String(value ?? ''); + if (str.includes(',') || str.includes('"') || str.includes('\n')) { + return `"${str.replace(/"/g, '""')}"`; + } + return str; +} + +/** + * Download selected features as a CSV file. + */ +export function exportToCSV( + features: GeoJsonFeature[], + filename?: string, +): void { + const { headers, rows } = featuresToRows(features); + const csvLines = [ + headers.map(escapeCSV).join(','), + ...rows.map(row => headers.map(h => escapeCSV(row[h])).join(',')), + ]; + const blob = new Blob([csvLines.join('\n')], { type: 'text/csv' }); + triggerDownload(blob, filename ?? `lasso-selection-${timestamp()}.csv`); +} + +/** + * Download selected features as an Excel (.xlsx) file. + * xlsx is lazy-loaded to avoid adding ~200KB to the initial bundle. + */ +export async function exportToExcel( + features: GeoJsonFeature[], + filename?: string, +): Promise { + const XLSX = await import('xlsx'); + const { headers, rows } = featuresToRows(features); + const ws = XLSX.utils.json_to_sheet(rows, { header: headers }); + const wb = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(wb, ws, 'Lasso Selection'); + XLSX.writeFile(wb, filename ?? `lasso-selection-${timestamp()}.xlsx`); +} diff --git a/superset-frontend/plugins/geoset-map-chart/src/utils/lassoSelection.ts b/superset-frontend/plugins/geoset-map-chart/src/utils/lassoSelection.ts new file mode 100644 index 0000000000..dea42711f0 --- /dev/null +++ b/superset-frontend/plugins/geoset-map-chart/src/utils/lassoSelection.ts @@ -0,0 +1,106 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import booleanPointInPolygon from '@turf/boolean-point-in-polygon'; +import centroid from '@turf/centroid'; +import { polygon as turfPolygon, point as turfPoint } from '@turf/helpers'; +import type { Coordinate } from './measureDistance'; +import type { GeoJsonFeature } from '../types'; + +export interface LassoSelectionResult { + features: GeoJsonFeature[]; + count: number; + byLayer: Record; +} + +/** + * Get a representative [lng, lat] for any GeoJSON geometry type. + * Points use coordinates directly; everything else uses @turf/centroid. + */ +export function getRepresentativePoint( + feature: GeoJsonFeature, +): [number, number] | null { + const { geometry } = feature; + if (!geometry || !geometry.type) return null; + + switch (geometry.type) { + case 'Point': + return geometry.coordinates as [number, number]; + case 'MultiPoint': + return geometry.coordinates?.[0] as [number, number] ?? null; + default: { + try { + const c = centroid(feature as any); + return c.geometry.coordinates as [number, number]; + } catch { + return null; + } + } + } +} + +/** + * Ensure a polygon coordinate ring is closed (first point == last point). + */ +function closeRing(coords: Coordinate[]): Coordinate[] { + if (coords.length < 3) return coords; + const first = coords[0]; + const last = coords[coords.length - 1]; + if (first[0] === last[0] && first[1] === last[1]) return coords; + return [...coords, first]; +} + +/** + * Filter features that have a representative point inside the lasso polygon. + */ +export function filterFeaturesInLasso( + features: GeoJsonFeature[], + lassoCoords: Coordinate[], +): GeoJsonFeature[] { + if (!features.length || lassoCoords.length < 3) return []; + + const closed = closeRing(lassoCoords); + const poly = turfPolygon([closed]); + + return features.filter(feature => { + const pt = getRepresentativePoint(feature); + if (!pt) return false; + return booleanPointInPolygon(turfPoint(pt), poly); + }); +} + +/** + * Filter features from multiple layers, returning per-layer breakdown. + */ +export function filterMultiLayerFeaturesInLasso( + layerFeatures: Record, + lassoCoords: Coordinate[], +): LassoSelectionResult { + const byLayer: Record = {}; + const allFeatures: GeoJsonFeature[] = []; + + Object.entries(layerFeatures).forEach(([layerName, features]) => { + const selected = filterFeaturesInLasso(features, lassoCoords); + if (selected.length > 0) { + byLayer[layerName] = selected; + allFeatures.push(...selected); + } + }); + + return { features: allFeatures, count: allFeatures.length, byLayer }; +} diff --git a/wiki/Development-Guide.md b/wiki/Development-Guide.md index 9d0d50116b..a55558239e 100644 --- a/wiki/Development-Guide.md +++ b/wiki/Development-Guide.md @@ -120,6 +120,8 @@ Each phase checks a staleness flag before proceeding. When the user changes a fi | `utils/liveViewportStore.ts` | Module-level store for live viewport state (bypasses Redux to avoid "Altered" chart state) | | `components/MultiLegend.tsx` | Drag-and-drop multi-layer legend with toggle/isolate | | `components/MapControls.tsx` | Zoom controls, measurement tool, and lasso select tool | +| `utils/lassoSelection.ts` | Point-in-polygon filtering for lasso-selected features | +| `utils/lassoExport.ts` | CSV and Excel export for lasso-selected features | ## Branch Strategy From ac9bf8da1a2f2e6a97e8d87b93f5e31e615ddfbc Mon Sep 17 00:00:00 2001 From: lhawkins Date: Tue, 24 Mar 2026 14:03:15 -0400 Subject: [PATCH 07/37] feat: Persist lasso polygon display and improve results bar UX Keep the completed lasso polygon visible (dashed outline + fill) after drawing finishes so users can see their selection area. Reposition the results bar from bottom-center to top-left, refine its styling, and auto-clear selection after CSV/Excel export. Add debug console logging for lasso selections. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../geoset-map-chart/src/DeckGLContainer.tsx | 3 + .../src/GeoSetMultiMap/Multi.tsx | 15 +++++ .../src/components/LassoOverlay.tsx | 64 ++++++++++++++++--- .../src/components/LassoResultsBar.tsx | 45 +++++++++---- .../src/layers/GeoSetLayer/GeoSetLayer.tsx | 19 ++++-- 5 files changed, 118 insertions(+), 28 deletions(-) diff --git a/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx b/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx index 25978b8be4..b9340adfc2 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx @@ -72,6 +72,7 @@ export type DeckGLContainerProps = { onMeasureDragEnd?: (coordinate: Coordinate) => void; lassoIsActive?: boolean; lassoDrawMode?: LassoDrawMode; + lassoPolygon?: Coordinate[] | null; onLassoComplete?: (polygon: Coordinate[]) => void; onEmptyClick?: () => void; }; @@ -380,11 +381,13 @@ export const DeckGLContainer = memo( // Get lasso editable layer (library-based drawing) const lassoIsActive = props.lassoIsActive ?? false; const lassoDrawMode = props.lassoDrawMode ?? 'freehand'; + const lassoPolygon = props.lassoPolygon ?? null; const handleLassoComplete = props.onLassoComplete ?? (() => {}); const { layers: lassoLayers } = useLassoLayer( lassoIsActive, handleLassoComplete, lassoDrawMode, + lassoPolygon, ); const allLayers = useMemo(() => { diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx index 93af9c494d..d0505f619d 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx @@ -1020,6 +1020,7 @@ const DeckMulti = (props: DeckMultiProps) => { selectedLassoLayerIds, selectedFeatures, setSelectedFeatures, + lassoPolygon, clearSelection, handleLassoToggle, handleLassoActivate, @@ -1060,6 +1061,19 @@ const DeckMulti = (props: DeckMultiProps) => { layerFeatureMap[name] = visibleFeatures; }); const result = filterMultiLayerFeaturesInLasso(layerFeatureMap, polygon); + // Debug: view lassoed data in browser console + console.group(`🔍 Lasso selected ${result.count} features`); + Object.entries(result.byLayer).forEach(([layer, feats]) => { + console.groupCollapsed(`${layer} (${feats.length})`); + console.table( + feats.map(f => ({ + geometryType: f.geometry?.type, + ...f.properties, + })), + ); + console.groupEnd(); + }); + console.groupEnd(); setSelectedFeatures(result.features); }, onActivate: () => { @@ -1201,6 +1215,7 @@ const DeckMulti = (props: DeckMultiProps) => { onMeasureDragEnd={handleMeasureDragEnd} lassoIsActive={lassoIsActive} lassoDrawMode={lassoDrawMode} + lassoPolygon={lassoPolygon} onLassoComplete={handleLassoComplete} onEmptyClick={handleClosePopup} /> diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx index 7e901c24f0..d2a55cb5a3 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx @@ -23,6 +23,9 @@ import { DrawPolygonMode, ViewMode, } from '@deck.gl-community/editable-layers'; +import { PathLayer } from '@deck.gl/layers'; +import { SolidPolygonLayer } from '@deck.gl/layers'; +import { PathStyleExtension } from '@deck.gl/extensions'; import type { Coordinate } from '../utils/measureDistance'; export type LassoDrawMode = 'freehand' | 'polygon'; @@ -46,13 +49,17 @@ const DRAW_MODES = { }; /** - * Hook to create an EditableGeoJsonLayer for lasso drawing. - * Supports freehand (drag) and point-to-point (click vertices, double-click to close). + * Hook to create layers for lasso drawing and completed polygon display. + * + * - While drawing: EditableGeoJsonLayer handles mouse interaction + * - After completion: separate SolidPolygonLayer (fill) + PathLayer (dashed outline) + * keep the polygon visible regardless of what the editable layer does */ export function useLassoLayer( isActive: boolean, onPolygonComplete: (polygon: Coordinate[]) => void, drawMode: LassoDrawMode = 'freehand', + completedPolygon: Coordinate[] | null = null, ): { layers: any[] } { const [data, setData] = useState(EMPTY_FEATURE_COLLECTION); const [mode, setMode] = useState( @@ -78,7 +85,6 @@ export function useLassoLayer( ({ updatedData, editType }: { updatedData: any; editType: string }) => { setData(updatedData); if (editType === 'addFeature') { - // Polygon drawing complete — extract coordinates and switch to view mode const lastFeature = updatedData.features[updatedData.features.length - 1]; const coords: number[][] = lastFeature.geometry.coordinates[0]; @@ -89,7 +95,8 @@ export function useLassoLayer( [onPolygonComplete], ); - const layers = useMemo(() => { + // Editable layer for drawing phase + const editableLayer = useMemo(() => { if (!isActive) return []; return [ @@ -100,19 +107,56 @@ export function useLassoLayer( selectedFeatureIndexes: [], onEdit: handleEdit, - // Completed polygon styling - getFillColor: [66, 133, 244, 40], - getLineColor: [50, 50, 50, 200], + getFillColor: [66, 133, 244, 30], + getLineColor: [40, 40, 40, 220], lineWidthMinPixels: 2, - // Tentative polygon styling (while drawing) - getTentativeFillColor: [66, 133, 244, 20], - getTentativeLineColor: [50, 50, 50, 180], + getTentativeFillColor: [66, 133, 244, 15], + getTentativeLineColor: [40, 40, 40, 200], pickable: true, }), ]; }, [isActive, data, mode, handleEdit]); + // Static layers for the completed polygon — persists after drawing finishes + const completedLayers = useMemo(() => { + if (!completedPolygon || completedPolygon.length < 3) return []; + + // Close the ring if needed + const ring = [...completedPolygon]; + const first = ring[0]; + const last = ring[ring.length - 1]; + if (first[0] !== last[0] || first[1] !== last[1]) { + ring.push(first); + } + + return [ + new SolidPolygonLayer({ + id: 'lasso-completed-fill', + data: [{ polygon: ring }], + getPolygon: (d: any) => d.polygon, + getFillColor: [66, 133, 244, 30], + pickable: false, + }), + new PathLayer({ + id: 'lasso-completed-outline', + data: [{ path: ring }], + getPath: (d: any) => d.path, + getColor: [40, 40, 40, 220], + widthMinPixels: 2, + getDashArray: [8, 4], + dashJustified: true, + extensions: [new PathStyleExtension({ dash: true })], + pickable: false, + }), + ]; + }, [completedPolygon]); + + const layers = useMemo( + () => [...editableLayer, ...completedLayers], + [editableLayer, completedLayers], + ); + return { layers }; } diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx index 1a6e854ab7..3d090dfbbd 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx @@ -27,11 +27,14 @@ export interface LassoResultsBarProps { onClear: () => void; } +const CONTROL_MARGIN = 12; +// MapControls bar height (32px) + gap +const TOP_OFFSET = 32 + CONTROL_MARGIN + 8; + const BarContainer = styled.div` position: absolute; - bottom: 12px; - left: 50%; - transform: translateX(-50%); + top: ${TOP_OFFSET}px; + left: ${CONTROL_MARGIN}px; z-index: 20; pointer-events: auto; `; @@ -40,8 +43,8 @@ const BarContent = styled.div( ({ theme }) => ` display: flex; align-items: center; - gap: 8px; - padding: 8px 12px; + gap: 4px; + padding: 10px 8px 10px 16px; background: ${theme.colorBgElevated}; border: 1px solid ${theme.colorBorderSecondary}; border-radius: 6px; @@ -52,9 +55,10 @@ const BarContent = styled.div( const CountLabel = styled.span( ({ theme }) => ` - font-size: 13px; - font-weight: 600; + font-size: 15px; + font-weight: 700; color: ${theme.colorText}; + margin-right: 4px; `, ); @@ -82,9 +86,9 @@ const IconButton = styled.button( const MenuPanel = styled.div( ({ theme }) => ` position: absolute; - bottom: calc(100% + 6px); - right: 0; - min-width: 160px; + top: 0; + left: calc(100% + 6px); + min-width: 170px; background: ${theme.colorBgElevated}; border: 1px solid ${theme.colorBorderSecondary}; border-radius: 6px; @@ -93,6 +97,16 @@ const MenuPanel = styled.div( `, ); +const MenuHeader = styled.div( + ({ theme }) => ` + padding: 8px 12px 6px; + font-size: 11px; + font-weight: 600; + color: ${theme.colorTextSecondary}; + border-bottom: 1px solid ${theme.colorBorderSecondary}; +`, +); + const MenuItem = styled.button<{ $disabled?: boolean }>( ({ theme, $disabled }) => ` display: flex; @@ -154,11 +168,14 @@ const DownloadIcon = () => ( ); -const LassoResultsBar = ({ count, features, onClear }: LassoResultsBarProps) => { +const LassoResultsBar = ({ + count, + features, + onClear, +}: LassoResultsBarProps) => { const [isMenuOpen, setIsMenuOpen] = useState(false); const containerRef = useRef(null); - // Close menu on outside click useEffect(() => { if (!isMenuOpen) return undefined; const handleOutsideClick = (e: MouseEvent) => { @@ -192,17 +209,19 @@ const LassoResultsBar = ({ count, features, onClear }: LassoResultsBarProps) => {isMenuOpen && ( + Download { exportToCSV(features); setIsMenuOpen(false); + onClear(); }} > Export to .CSV { - exportToExcel(features); + exportToExcel(features).then(() => onClear()); setIsMenuOpen(false); }} > diff --git a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx index 9d1053df94..d117685f4e 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx @@ -18,7 +18,6 @@ * under the License. */ import { memo, useCallback, useMemo, useRef, useState, useEffect } from 'react'; -import { useLassoSelection } from '../../hooks/useLassoSelection'; import { GeoJsonLayer, IconLayer, @@ -40,6 +39,7 @@ import { } from '@superset-ui/core'; import { Alert } from 'antd'; import Layer from '@deck.gl/core/dist/lib/layer'; +import { useLassoSelection } from '../../hooks/useLassoSelection'; import { DeckGLContainerHandle, DeckGLContainerStyledWrapper, @@ -956,6 +956,7 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { setLassoDrawMode, selectedFeatures, setSelectedFeatures, + lassoPolygon, clearSelection, handleLassoToggle, handleLassoActivate, @@ -963,8 +964,7 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { deactivateLasso, } = useLassoSelection({ onPolygonComplete: polygon => { - const allFeatures = - (payload?.data?.features as GeoJsonFeature[]) || []; + const allFeatures = (payload?.data?.features as GeoJsonFeature[]) || []; const dimension = propVisualConfig?.dimension as string | undefined; // Only include features whose category is visible in the legend @@ -976,8 +976,7 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { const visibleFeatures = disabledKeys.size > 0 && dimension ? allFeatures.filter(f => { - const raw = - (f as any).categoryName ?? f.properties?.[dimension]; + const raw = (f as any).categoryName ?? f.properties?.[dimension]; if (raw == null) return true; const key = typeof raw === 'string' @@ -988,6 +987,15 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { : allFeatures; const selected = filterFeaturesInLasso(visibleFeatures, polygon); + // Debug: view lassoed data in browser console + console.group(`🔍 Lasso selected ${selected.length} features`); + console.table( + selected.map(f => ({ + geometryType: f.geometry?.type, + ...f.properties, + })), + ); + console.groupEnd(); setSelectedFeatures(selected); }, onActivate: () => { @@ -1258,6 +1266,7 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { onMeasureDragEnd={handleMeasureDragEnd} lassoIsActive={lassoIsActive} lassoDrawMode={lassoDrawMode} + lassoPolygon={lassoPolygon} onLassoComplete={handleLassoComplete} onEmptyClick={handleClosePopup} /> From 23d5ac47b9f7ec2479af4fb76fc567717f01cfdd Mon Sep 17 00:00:00 2001 From: lhawkins Date: Tue, 24 Mar 2026 14:04:33 -0400 Subject: [PATCH 08/37] docs: Add missing lasso component entries to Development Guide Add LassoOverlay, LassoResultsBar, and useLassoSelection hook to the Key Utilities table in the Development Guide wiki page. Co-Authored-By: Claude Opus 4.6 (1M context) --- wiki/Development-Guide.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wiki/Development-Guide.md b/wiki/Development-Guide.md index a55558239e..bf4c1f6da8 100644 --- a/wiki/Development-Guide.md +++ b/wiki/Development-Guide.md @@ -120,6 +120,9 @@ Each phase checks a staleness flag before proceeding. When the user changes a fi | `utils/liveViewportStore.ts` | Module-level store for live viewport state (bypasses Redux to avoid "Altered" chart state) | | `components/MultiLegend.tsx` | Drag-and-drop multi-layer legend with toggle/isolate | | `components/MapControls.tsx` | Zoom controls, measurement tool, and lasso select tool | +| `components/LassoOverlay.tsx` | Lasso drawing layers (freehand and point-to-point polygon modes) via `useLassoLayer` hook | +| `components/LassoResultsBar.tsx` | Selection count bar with CSV/Excel export menu | +| `hooks/useLassoSelection.ts` | Shared React hook managing lasso state, polygon completion, and multi-layer selection | | `utils/lassoSelection.ts` | Point-in-polygon filtering for lasso-selected features | | `utils/lassoExport.ts` | CSV and Excel export for lasso-selected features | From ca3f08086bef6108485be1590aea2343f7ec7aa2 Mon Sep 17 00:00:00 2001 From: lhawkins Date: Tue, 24 Mar 2026 16:43:42 -0400 Subject: [PATCH 09/37] feat: Switch lasso to single-layer selection and geometry-aware filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace multi-layer checkbox selection with single-layer radio selection for the lasso tool. Upgrade lasso filtering from centroid-based to geometry-aware intersection — points use direct containment, polygons are selected when ≥50% of their area overlaps the lasso region via @turf/intersect. Add @turf/area, @turf/intersect, @turf/boolean-within dependencies. Co-Authored-By: Claude Opus 4.6 (1M context) --- superset-frontend/package-lock.json | 127 +++++++++++++++--- superset-frontend/package.json | 2 + .../plugins/geoset-map-chart/package.json | 3 + .../src/GeoSetMultiMap/Multi.tsx | 10 +- .../src/components/MapControls.tsx | 53 +++----- .../src/hooks/useLassoSelection.ts | 35 +++-- .../src/utils/lassoSelection.ts | 63 +++++++-- .../test/components/MapControls.test.tsx | 19 ++- 8 files changed, 217 insertions(+), 95 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 9dc9042b26..b8133f5a9c 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -21,6 +21,7 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@material-ui/core": "^4.12.4", + "@react-spring/web": "^9.7.5", "@reduxjs/toolkit": "^1.9.3", "@rjsf/core": "^5.21.1", "@rjsf/utils": "^5.24.3", @@ -49,6 +50,7 @@ "@superset-ui/plugin-chart-table": "file:./plugins/plugin-chart-table", "@superset-ui/plugin-chart-word-cloud": "file:./plugins/plugin-chart-word-cloud", "@superset-ui/switchboard": "file:./packages/superset-ui-switchboard", + "@turf/boolean-intersects": "^7.3.4", "@types/d3-format": "^3.0.1", "@types/d3-time-format": "^4.0.3", "@types/react-google-recaptcha": "^2.1.9", @@ -9997,7 +9999,6 @@ "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz", "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", "license": "MIT", - "peer": true, "dependencies": { "@react-spring/shared": "~9.7.5", "@react-spring/types": "~9.7.5" @@ -10011,7 +10012,6 @@ "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz", "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", "license": "MIT", - "peer": true, "dependencies": { "@react-spring/animated": "~9.7.5", "@react-spring/shared": "~9.7.5", @@ -10029,15 +10029,13 @@ "version": "9.7.5", "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.5.tgz", "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@react-spring/shared": { "version": "9.7.5", "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz", "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", "license": "MIT", - "peer": true, "dependencies": { "@react-spring/rafz": "~9.7.5", "@react-spring/types": "~9.7.5" @@ -10050,15 +10048,13 @@ "version": "9.7.5", "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.5.tgz", "integrity": "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@react-spring/web": { "version": "9.7.5", "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.5.tgz", "integrity": "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ==", "license": "MIT", - "peer": true, "dependencies": { "@react-spring/animated": "~9.7.5", "@react-spring/core": "~9.7.5", @@ -14309,6 +14305,94 @@ "@turf/invariant": "^5.1.5" } }, + "node_modules/@turf/boolean-disjoint": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/boolean-disjoint/-/boolean-disjoint-7.3.4.tgz", + "integrity": "sha512-Dl4O27ygi2NqskGQuvSlDLJYlJ2SPkHb3A9T/v6eAudjlMiKdEY6bMxKUfU5y+Px1WiCZxd+9rXGXJgGC3WiQg==", + "license": "MIT", + "dependencies": { + "@turf/boolean-point-in-polygon": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/line-intersect": "7.3.4", + "@turf/meta": "7.3.4", + "@turf/polygon-to-line": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-disjoint/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-disjoint/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-intersects": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/boolean-intersects/-/boolean-intersects-7.3.4.tgz", + "integrity": "sha512-sxi41NXkb5hrJgOvpm32hyBLhW8fem0vn2XxR4+jyRg1rM/v3ziF10/VqC9KDZuDNZkt9JjL9B0825Cf7AN6Lg==", + "license": "MIT", + "dependencies": { + "@turf/boolean-disjoint": "7.3.4", + "@turf/helpers": "7.3.4", + "@turf/meta": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-intersects/node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-intersects/node_modules/@turf/meta": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.4.tgz", + "integrity": "sha512-tlmw9/Hs1p2n0uoHVm1w3ugw1I6L8jv9YZrcdQa4SH5FX5UY0ATrKeIvfA55FlL//PGuYppJp+eyg/0eb4goqw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, "node_modules/@turf/boolean-point-in-polygon": { "version": "7.3.4", "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-7.3.4.tgz", @@ -23636,9 +23720,9 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "15.12.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.12.0.tgz", - "integrity": "sha512-B2BRcudLfA4NZZP5QpA45J70bu1heCH59V1yKRLHAtiC49r7RV03X5ifUh7Nfbk8QNg93RAsc6oAmodm/+j0pA==", + "version": "15.13.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.13.0.tgz", + "integrity": "sha512-hJ9sY++TUC/HlUzHVJpIrDyqKMjlhx5PTXl/A7eA91JNEtUWkJAqefQR5mo9AtLra/9+m+JJaMg2U5Qd0a74Fw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -33537,9 +33621,9 @@ } }, "node_modules/istanbul-lib-processinfo/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "peer": true, @@ -43334,9 +43418,9 @@ } }, "node_modules/nyc/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "peer": true, @@ -52384,9 +52468,9 @@ } }, "node_modules/spawn-wrap/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "peer": true, @@ -59531,9 +59615,12 @@ "@mapbox/geojson-extent": "^1.0.1", "@material-ui/icons": "^4.11.3", "@math.gl/web-mercator": "^4.1.0", + "@turf/area": "^7.2.0", "@turf/boolean-point-in-polygon": "^7.2.0", + "@turf/boolean-within": "^7.2.0", "@turf/centroid": "^7.2.0", "@turf/helpers": "^7.2.0", + "@turf/intersect": "^7.2.0", "@types/d3-array": "^2.0.0", "@types/d3-interpolate": "^3.0.4", "@types/d3-scale-chromatic": "^3.1.0", diff --git a/superset-frontend/package.json b/superset-frontend/package.json index aea252781f..d7b35a518a 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -89,6 +89,7 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@material-ui/core": "^4.12.4", + "@react-spring/web": "^9.7.5", "@reduxjs/toolkit": "^1.9.3", "@rjsf/core": "^5.21.1", "@rjsf/utils": "^5.24.3", @@ -117,6 +118,7 @@ "@superset-ui/plugin-chart-table": "file:./plugins/plugin-chart-table", "@superset-ui/plugin-chart-word-cloud": "file:./plugins/plugin-chart-word-cloud", "@superset-ui/switchboard": "file:./packages/superset-ui-switchboard", + "@turf/boolean-intersects": "^7.3.4", "@types/d3-format": "^3.0.1", "@types/d3-time-format": "^4.0.3", "@types/react-google-recaptcha": "^2.1.9", diff --git a/superset-frontend/plugins/geoset-map-chart/package.json b/superset-frontend/plugins/geoset-map-chart/package.json index f0d3731cd9..37a05fe75d 100644 --- a/superset-frontend/plugins/geoset-map-chart/package.json +++ b/superset-frontend/plugins/geoset-map-chart/package.json @@ -26,7 +26,10 @@ "dependencies": { "@ant-design/icons": "^5.6.1", "@deck.gl-community/editable-layers": "^9.2.8", + "@turf/boolean-within": "^7.2.0", + "@turf/area": "^7.2.0", "@turf/boolean-point-in-polygon": "^7.2.0", + "@turf/intersect": "^7.2.0", "@turf/centroid": "^7.2.0", "@turf/helpers": "^7.2.0", "@deck.gl/aggregation-layers": "^9.1.14", diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx index d0505f619d..fd02d73569 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx @@ -1017,7 +1017,7 @@ const DeckMulti = (props: DeckMultiProps) => { lassoIsActive, lassoDrawMode, setLassoDrawMode, - selectedLassoLayerIds, + selectedLassoLayerId, selectedFeatures, setSelectedFeatures, lassoPolygon, @@ -1025,7 +1025,7 @@ const DeckMulti = (props: DeckMultiProps) => { handleLassoToggle, handleLassoActivate, handleLassoComplete, - handleLassoLayerToggle, + handleLassoLayerSelect, deactivateLasso, } = useLassoSelection({ availableLayers: lassoLayers, @@ -1033,7 +1033,7 @@ const DeckMulti = (props: DeckMultiProps) => { const layerFeatureMap: Record = {}; sortedLayers.forEach(entry => { const layerId = String(entry.sliceId); - if (!selectedLassoLayerIds.includes(layerId)) return; + if (layerId !== selectedLassoLayerId) return; const allFeatures = (entry.transformedProps.payload?.data @@ -1235,8 +1235,8 @@ const DeckMulti = (props: DeckMultiProps) => { onLassoActivate={handleLassoActivate} isLassoActive={lassoIsActive} lassoLayers={lassoLayers} - activeLassoLayerIds={selectedLassoLayerIds} - onLassoLayerToggle={handleLassoLayerToggle} + activeLassoLayerId={selectedLassoLayerId} + onLassoLayerSelect={handleLassoLayerSelect} lassoDrawMode={lassoDrawMode} onLassoDrawModeChange={setLassoDrawMode} position="top-right" diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx index d0e35c3472..fe368f2aea 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx @@ -33,8 +33,8 @@ export type MapControlsProps = { onLassoActivate?: () => void; isLassoActive: boolean; lassoLayers?: LassoLayer[]; - activeLassoLayerIds?: string[]; - onLassoLayerToggle?: (layerId: string) => void; + activeLassoLayerId?: string; + onLassoLayerSelect?: (layerId: string) => void; lassoDrawMode?: LassoDrawMode; onLassoDrawModeChange?: (mode: LassoDrawMode) => void; position?: 'top-left' | 'top-right'; @@ -228,28 +228,17 @@ const PolygonIcon = () => ( ); -const CheckboxIcon = ({ checked }: { checked: boolean }) => ( +const RadioIcon = ({ selected }: { selected: boolean }) => ( - - {checked && ( - - )} + {selected && } ); @@ -316,8 +305,8 @@ const MapControls = ({ onLassoActivate, isLassoActive, lassoLayers = [], - activeLassoLayerIds = [], - onLassoLayerToggle, + activeLassoLayerId, + onLassoLayerSelect, lassoDrawMode = 'freehand', onLassoDrawModeChange, position = 'top-left', @@ -335,8 +324,8 @@ const MapControls = ({ !containerRef.current.contains(e.target as Node) ) { setIsDropdownOpen(false); - // Multi-layer requires at least one layer selected; single-layer always activates - if (!hasMultipleLayers || activeLassoLayerIds.length > 0) { + // Multi-layer requires a layer selected; single-layer always activates + if (!hasMultipleLayers || activeLassoLayerId) { onLassoActivate?.(); } } @@ -346,7 +335,7 @@ const MapControls = ({ }, [ isDropdownOpen, hasMultipleLayers, - activeLassoLayerIds.length, + activeLassoLayerId, onLassoActivate, ]); @@ -359,13 +348,13 @@ const MapControls = ({ } }; - const handleLayerToggle = (layerId: string) => { - onLassoLayerToggle?.(layerId); + const handleLayerSelect = (layerId: string) => { + onLassoLayerSelect?.(layerId); }; const handleCloseDropdown = () => { setIsDropdownOpen(false); - if (!hasMultipleLayers || activeLassoLayerIds.length > 0) { + if (!hasMultipleLayers || activeLassoLayerId) { onLassoActivate?.(); } }; @@ -403,20 +392,20 @@ const MapControls = ({ {isDropdownOpen && ( - {hasMultipleLayers ? 'Select layers' : 'Lasso mode'} + {hasMultipleLayers ? 'Select layer' : 'Lasso mode'} {hasMultipleLayers && lassoLayers.map(layer => { - const isChecked = activeLassoLayerIds.includes(layer.id); + const isSelected = layer.id === activeLassoLayerId; return ( handleLayerToggle(layer.id)} + onClick={() => handleLayerSelect(layer.id)} > - + {layer.name} ); diff --git a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts index f6b900db50..7b0d9e4604 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts +++ b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts @@ -35,7 +35,7 @@ export type UseLassoSelectionResult = { lassoIsActive: boolean; lassoDrawMode: LassoDrawMode; setLassoDrawMode: (mode: LassoDrawMode) => void; - selectedLassoLayerIds: string[]; + selectedLassoLayerId: string | undefined; selectedFeatures: GeoJsonFeature[]; setSelectedFeatures: (features: GeoJsonFeature[]) => void; lassoPolygon: Coordinate[] | null; @@ -43,7 +43,7 @@ export type UseLassoSelectionResult = { handleLassoToggle: () => void; handleLassoActivate: () => void; handleLassoComplete: (polygon: Coordinate[]) => void; - handleLassoLayerToggle: (layerId: string) => void; + handleLassoLayerSelect: (layerId: string) => void; deactivateLasso: () => void; }; @@ -60,20 +60,19 @@ export function useLassoSelection( const [lassoIsActive, setLassoIsActive] = useState(false); const [lassoDrawMode, setLassoDrawMode] = useState('freehand'); - const [selectedLassoLayerIds, setSelectedLassoLayerIds] = useState( - [], - ); + const [selectedLassoLayerId, setSelectedLassoLayerId] = useState< + string | undefined + >(); const [selectedFeatures, setSelectedFeatures] = useState( [], ); const [lassoPolygon, setLassoPolygon] = useState(null); - // Auto-select the first layer when available layers load and none are selected. - // Serialize IDs as the dependency so the effect only fires when actual layers change. + // Auto-select the first layer when available layers load and none is selected. const availableLayerIds = availableLayers.map(l => l.id).join(','); useEffect(() => { - if (availableLayers.length > 0 && selectedLassoLayerIds.length === 0) { - setSelectedLassoLayerIds([availableLayers[0].id]); + if (availableLayers.length > 0 && !selectedLassoLayerId) { + setSelectedLassoLayerId(availableLayers[0].id); } }, [availableLayerIds]); // eslint-disable-line react-hooks/exhaustive-deps @@ -87,10 +86,10 @@ export function useLassoSelection( setLassoPolygon(null); }, []); - // Toggle lasso off — full reset including layer selections and results + // Toggle lasso off — full reset including layer selection and results const handleLassoToggle = useCallback(() => { setLassoIsActive(false); - setSelectedLassoLayerIds([]); + setSelectedLassoLayerId(undefined); setSelectedFeatures([]); setLassoPolygon(null); }, []); @@ -107,13 +106,9 @@ export function useLassoSelection( onPolygonCompleteRef.current?.(polygon); }, []); - // Toggle a layer in/out of the multi-layer selection - const handleLassoLayerToggle = useCallback((layerId: string) => { - setSelectedLassoLayerIds(prev => - prev.includes(layerId) - ? prev.filter(id => id !== layerId) - : [...prev, layerId], - ); + // Select a single layer for lasso + const handleLassoLayerSelect = useCallback((layerId: string) => { + setSelectedLassoLayerId(layerId); }, []); // Escape key exits lasso mode @@ -135,7 +130,7 @@ export function useLassoSelection( lassoIsActive, lassoDrawMode, setLassoDrawMode, - selectedLassoLayerIds, + selectedLassoLayerId, selectedFeatures, setSelectedFeatures, lassoPolygon, @@ -143,7 +138,7 @@ export function useLassoSelection( handleLassoToggle, handleLassoActivate, handleLassoComplete, - handleLassoLayerToggle, + handleLassoLayerSelect, deactivateLasso, }; } diff --git a/superset-frontend/plugins/geoset-map-chart/src/utils/lassoSelection.ts b/superset-frontend/plugins/geoset-map-chart/src/utils/lassoSelection.ts index dea42711f0..434a82ab0c 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/utils/lassoSelection.ts +++ b/superset-frontend/plugins/geoset-map-chart/src/utils/lassoSelection.ts @@ -16,12 +16,17 @@ * specific language governing permissions and limitations * under the License. */ +import area from '@turf/area'; import booleanPointInPolygon from '@turf/boolean-point-in-polygon'; import centroid from '@turf/centroid'; +import intersect from '@turf/intersect'; import { polygon as turfPolygon, point as turfPoint } from '@turf/helpers'; import type { Coordinate } from './measureDistance'; import type { GeoJsonFeature } from '../types'; +/** Minimum overlap ratio (0–1) for a polygon to be captured by the lasso. */ +const POLYGON_OVERLAP_THRESHOLD = 0.5; + export interface LassoSelectionResult { features: GeoJsonFeature[]; count: number; @@ -30,7 +35,7 @@ export interface LassoSelectionResult { /** * Get a representative [lng, lat] for any GeoJSON geometry type. - * Points use coordinates directly; everything else uses @turf/centroid. + * Used for point features and as a fallback for export coordinates. */ export function getRepresentativePoint( feature: GeoJsonFeature, @@ -42,7 +47,7 @@ export function getRepresentativePoint( case 'Point': return geometry.coordinates as [number, number]; case 'MultiPoint': - return geometry.coordinates?.[0] as [number, number] ?? null; + return (geometry.coordinates?.[0] as [number, number]) ?? null; default: { try { const c = centroid(feature as any); @@ -66,7 +71,53 @@ function closeRing(coords: Coordinate[]): Coordinate[] { } /** - * Filter features that have a representative point inside the lasso polygon. + * Test whether a feature intersects the lasso polygon. + * + * - Point / MultiPoint: direct point-in-polygon test (fast) + * - Polygon / LineString / etc.: boolean intersects test — + * selected if any part of the geometry overlaps the lasso area + */ +function isFeatureInLasso( + feature: GeoJsonFeature, + lassoPoly: ReturnType, +): boolean { + const { geometry } = feature; + if (!geometry || !geometry.type) return false; + + try { + switch (geometry.type) { + case 'Point': { + const pt = geometry.coordinates as [number, number]; + return booleanPointInPolygon(turfPoint(pt), lassoPoly); + } + case 'MultiPoint': { + // Selected if any point in the multi-point is inside + return (geometry.coordinates as [number, number][]).some(pt => + booleanPointInPolygon(turfPoint(pt), lassoPoly), + ); + } + case 'Polygon': + case 'MultiPolygon': { + // Selected if >= 50% of the polygon's area is inside the lasso + const featureArea = area(feature as any); + if (featureArea === 0) return false; + const overlap = intersect( + { type: 'FeatureCollection', features: [feature as any, lassoPoly] }, + ); + if (!overlap) return false; + return area(overlap) / featureArea >= POLYGON_OVERLAP_THRESHOLD; + } + default: + // LineString, MultiLineString, GeometryCollection — skip + return false; + } + } catch { + return false; + } +} + +/** + * Filter features that intersect the lasso polygon. */ export function filterFeaturesInLasso( features: GeoJsonFeature[], @@ -77,11 +128,7 @@ export function filterFeaturesInLasso( const closed = closeRing(lassoCoords); const poly = turfPolygon([closed]); - return features.filter(feature => { - const pt = getRepresentativePoint(feature); - if (!pt) return false; - return booleanPointInPolygon(turfPoint(pt), poly); - }); + return features.filter(feature => isFeatureInLasso(feature, poly)); } /** diff --git a/superset-frontend/plugins/geoset-map-chart/test/components/MapControls.test.tsx b/superset-frontend/plugins/geoset-map-chart/test/components/MapControls.test.tsx index 8057e8644d..d05660721d 100644 --- a/superset-frontend/plugins/geoset-map-chart/test/components/MapControls.test.tsx +++ b/superset-frontend/plugins/geoset-map-chart/test/components/MapControls.test.tsx @@ -118,30 +118,30 @@ describe('Lasso — multi-layer', () => { { id: '3', name: 'Air Quality' }, ]; - it('opens dropdown with "Select layers" header and layer list', () => { + it('opens dropdown with "Select layer" header and layer list', () => { renderMapControls({ lassoLayers: layers }); userEvent.click(screen.getByTitle('Lasso select features')); - expect(screen.getByText('Select layers')).toBeInTheDocument(); + expect(screen.getByText('Select layer')).toBeInTheDocument(); expect(screen.getByText('Burn Areas')).toBeInTheDocument(); expect(screen.getByText('Program Offices')).toBeInTheDocument(); expect(screen.getByText('Air Quality')).toBeInTheDocument(); }); - it('calls onLassoLayerToggle when a layer is clicked', () => { - const onLassoLayerToggle = jest.fn(); - renderMapControls({ lassoLayers: layers, onLassoLayerToggle }); + it('calls onLassoLayerSelect when a layer is clicked', () => { + const onLassoLayerSelect = jest.fn(); + renderMapControls({ lassoLayers: layers, onLassoLayerSelect }); userEvent.click(screen.getByTitle('Lasso select features')); userEvent.click(screen.getByText('Program Offices')); - expect(onLassoLayerToggle).toHaveBeenCalledWith('2'); + expect(onLassoLayerSelect).toHaveBeenCalledWith('2'); }); - it('calls onLassoActivate on close when layers are selected', () => { + it('calls onLassoActivate on close when a layer is selected', () => { const onLassoActivate = jest.fn(); renderMapControls({ lassoLayers: layers, - activeLassoLayerIds: ['2'], + activeLassoLayerId: '2', onLassoActivate, }); @@ -150,11 +150,10 @@ describe('Lasso — multi-layer', () => { expect(onLassoActivate).toHaveBeenCalledTimes(1); }); - it('does NOT call onLassoActivate on close when no layers selected', () => { + it('does NOT call onLassoActivate on close when no layer selected', () => { const onLassoActivate = jest.fn(); renderMapControls({ lassoLayers: layers, - activeLassoLayerIds: [], onLassoActivate, }); From 46129858f0847c5aac21e588961dcc1f6b150e81 Mon Sep 17 00:00:00 2001 From: lhawkins Date: Tue, 24 Mar 2026 16:44:19 -0400 Subject: [PATCH 10/37] docs: Update lasso documentation for single-layer selection and geometry filtering Reflect the switch from multi-layer to single-layer selection in the Development Guide and inline comments. Update lassoSelection.ts description to mention geometry-aware intersection filtering. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../plugins/geoset-map-chart/src/hooks/useLassoSelection.ts | 2 +- wiki/Development-Guide.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts index 7b0d9e4604..a4d96e58a1 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts +++ b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts @@ -23,7 +23,7 @@ import type { LassoLayer } from '../components/MapControls'; import type { GeoJsonFeature } from '../types'; export type UseLassoSelectionOptions = { - /** Available layers for multi-layer selection. Omit or pass empty for single-layer. */ + /** Available layers for lasso selection. Omit or pass empty for single-layer. */ availableLayers?: LassoLayer[]; /** Called when lasso polygon drawing completes. */ onPolygonComplete?: (polygon: Coordinate[]) => void; diff --git a/wiki/Development-Guide.md b/wiki/Development-Guide.md index bf4c1f6da8..a479f82999 100644 --- a/wiki/Development-Guide.md +++ b/wiki/Development-Guide.md @@ -122,8 +122,8 @@ Each phase checks a staleness flag before proceeding. When the user changes a fi | `components/MapControls.tsx` | Zoom controls, measurement tool, and lasso select tool | | `components/LassoOverlay.tsx` | Lasso drawing layers (freehand and point-to-point polygon modes) via `useLassoLayer` hook | | `components/LassoResultsBar.tsx` | Selection count bar with CSV/Excel export menu | -| `hooks/useLassoSelection.ts` | Shared React hook managing lasso state, polygon completion, and multi-layer selection | -| `utils/lassoSelection.ts` | Point-in-polygon filtering for lasso-selected features | +| `hooks/useLassoSelection.ts` | Shared React hook managing lasso state, polygon completion, and layer selection | +| `utils/lassoSelection.ts` | Geometric intersection filtering (point-in-polygon and area-overlap) for lasso-selected features | | `utils/lassoExport.ts` | CSV and Excel export for lasso-selected features | ## Branch Strategy From 271406176854a083ced88d69d2235e79e29a4bcb Mon Sep 17 00:00:00 2001 From: lhawkins Date: Tue, 24 Mar 2026 17:24:12 -0400 Subject: [PATCH 11/37] feat: Anchor lasso results bar near end of drawn polygon Position the LassoResultsBar at the screen coordinates of the last lasso polygon point instead of a fixed top-left corner. Add anchorPosition state to useLassoSelection hook, project the final polygon coordinate via WebMercatorViewport, and pass it through to both single-layer and multi-layer map components. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/GeoSetMultiMap/Multi.tsx | 12 ++++++++++++ .../src/components/LassoResultsBar.tsx | 17 ++++++++++++----- .../src/hooks/useLassoSelection.ts | 11 +++++++++++ .../src/layers/GeoSetLayer/GeoSetLayer.tsx | 12 ++++++++++++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx index fd02d73569..26cf61bbc5 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx @@ -21,6 +21,7 @@ */ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { isEqual } from 'lodash'; +import { WebMercatorViewport } from '@math.gl/web-mercator'; import { Datasource, HandlerFunction, @@ -1021,6 +1022,8 @@ const DeckMulti = (props: DeckMultiProps) => { selectedFeatures, setSelectedFeatures, lassoPolygon, + anchorPosition, + setAnchorPosition, clearSelection, handleLassoToggle, handleLassoActivate, @@ -1075,6 +1078,14 @@ const DeckMulti = (props: DeckMultiProps) => { }); console.groupEnd(); setSelectedFeatures(result.features); + + // Anchor the results bar near the end of the lasso + const lastCoord = polygon[polygon.length - 1]; + if (lastCoord) { + const wmv = new WebMercatorViewport({ ...viewport, width, height }); + const [px, py] = wmv.project(lastCoord); + setAnchorPosition({ x: px, y: py + 12 }); + } }, onActivate: () => { setMeasureState({ @@ -1246,6 +1257,7 @@ const DeckMulti = (props: DeckMultiProps) => { count={selectedFeatures.length} features={selectedFeatures} onClear={clearSelection} + anchorPosition={anchorPosition} /> )} {clickedFeature && ( diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx index 3d090dfbbd..3d02b61d21 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx @@ -25,16 +25,18 @@ export interface LassoResultsBarProps { count: number; features: GeoJsonFeature[]; onClear: () => void; + anchorPosition?: { x: number; y: number } | null; } const CONTROL_MARGIN = 12; -// MapControls bar height (32px) + gap const TOP_OFFSET = 32 + CONTROL_MARGIN + 8; -const BarContainer = styled.div` +const BarContainer = styled.div<{ $x?: number; $y?: number }>` position: absolute; - top: ${TOP_OFFSET}px; - left: ${CONTROL_MARGIN}px; + ${({ $x, $y }) => + $x != null && $y != null + ? `left: ${$x}px; top: ${$y}px;` + : `left: ${CONTROL_MARGIN}px; top: ${TOP_OFFSET}px;`} z-index: 20; pointer-events: auto; `; @@ -172,6 +174,7 @@ const LassoResultsBar = ({ count, features, onClear, + anchorPosition, }: LassoResultsBarProps) => { const [isMenuOpen, setIsMenuOpen] = useState(false); const containerRef = useRef(null); @@ -193,7 +196,11 @@ const LassoResultsBar = ({ if (count === 0) return null; return ( - + {count} Items Selected void; lassoPolygon: Coordinate[] | null; + anchorPosition: { x: number; y: number } | null; + setAnchorPosition: (pos: { x: number; y: number } | null) => void; clearSelection: () => void; handleLassoToggle: () => void; handleLassoActivate: () => void; @@ -67,6 +69,10 @@ export function useLassoSelection( [], ); const [lassoPolygon, setLassoPolygon] = useState(null); + const [anchorPosition, setAnchorPosition] = useState<{ + x: number; + y: number; + } | null>(null); // Auto-select the first layer when available layers load and none is selected. const availableLayerIds = availableLayers.map(l => l.id).join(','); @@ -84,6 +90,7 @@ export function useLassoSelection( const clearSelection = useCallback(() => { setSelectedFeatures([]); setLassoPolygon(null); + setAnchorPosition(null); }, []); // Toggle lasso off — full reset including layer selection and results @@ -91,6 +98,7 @@ export function useLassoSelection( setLassoIsActive(false); setSelectedLassoLayerId(undefined); setSelectedFeatures([]); + setAnchorPosition(null); setLassoPolygon(null); }, []); @@ -120,6 +128,7 @@ export function useLassoSelection( setLassoIsActive(false); setSelectedFeatures([]); setLassoPolygon(null); + setAnchorPosition(null); } }; document.addEventListener('keydown', handleKeyDown); @@ -134,6 +143,8 @@ export function useLassoSelection( selectedFeatures, setSelectedFeatures, lassoPolygon, + anchorPosition, + setAnchorPosition, clearSelection, handleLassoToggle, handleLassoActivate, diff --git a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx index d117685f4e..099a241495 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx @@ -38,6 +38,7 @@ import { QueryFormData, } from '@superset-ui/core'; import { Alert } from 'antd'; +import { WebMercatorViewport } from '@math.gl/web-mercator'; import Layer from '@deck.gl/core/dist/lib/layer'; import { useLassoSelection } from '../../hooks/useLassoSelection'; import { @@ -957,6 +958,8 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { selectedFeatures, setSelectedFeatures, lassoPolygon, + anchorPosition, + setAnchorPosition, clearSelection, handleLassoToggle, handleLassoActivate, @@ -997,6 +1000,14 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { ); console.groupEnd(); setSelectedFeatures(selected); + + // Anchor the results bar near the end of the lasso + const lastCoord = polygon[polygon.length - 1]; + if (lastCoord) { + const wmv = new WebMercatorViewport({ ...viewport, width, height }); + const [px, py] = wmv.project(lastCoord); + setAnchorPosition({ x: px, y: py + 12 }); + } }, onActivate: () => { setMeasureState({ @@ -1302,6 +1313,7 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { count={selectedFeatures.length} features={selectedFeatures} onClear={clearSelection} + anchorPosition={anchorPosition} /> )} Date: Wed, 25 Mar 2026 09:47:43 -0400 Subject: [PATCH 12/37] fix: Stabilize lasso memoization, fix broken tests, and simplify code Fix critical memoization cascade where EditableGeoJsonLayer was reconstructed every render due to unstable onPolygonComplete references. Update useLassoSelection tests to match current single-select API. Extract LassoDropdown component, remove debug console statements, unused deps, and drifting anchor positioning. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../plugins/geoset-map-chart/package.json | 1 - .../geoset-map-chart/src/DeckGLContainer.tsx | 3 +- .../src/GeoSetMultiMap/Multi.tsx | 25 -- .../src/components/LassoDropdown.tsx | 225 ++++++++++++++++++ .../src/components/LassoOverlay.tsx | 21 +- .../src/components/LassoResultsBar.tsx | 23 +- .../src/components/MapControls.tsx | 207 +--------------- .../src/hooks/useLassoSelection.ts | 11 - .../src/layers/GeoSetLayer/GeoSetLayer.tsx | 21 -- .../src/utils/lassoSelection.ts | 2 +- .../test/hooks/useLassoSelection.test.ts | 45 ++-- 11 files changed, 282 insertions(+), 302 deletions(-) create mode 100644 superset-frontend/plugins/geoset-map-chart/src/components/LassoDropdown.tsx diff --git a/superset-frontend/plugins/geoset-map-chart/package.json b/superset-frontend/plugins/geoset-map-chart/package.json index 37a05fe75d..5a7eb56ea0 100644 --- a/superset-frontend/plugins/geoset-map-chart/package.json +++ b/superset-frontend/plugins/geoset-map-chart/package.json @@ -26,7 +26,6 @@ "dependencies": { "@ant-design/icons": "^5.6.1", "@deck.gl-community/editable-layers": "^9.2.8", - "@turf/boolean-within": "^7.2.0", "@turf/area": "^7.2.0", "@turf/boolean-point-in-polygon": "^7.2.0", "@turf/intersect": "^7.2.0", diff --git a/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx b/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx index b9340adfc2..140f0ef7d4 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx @@ -382,7 +382,8 @@ export const DeckGLContainer = memo( const lassoIsActive = props.lassoIsActive ?? false; const lassoDrawMode = props.lassoDrawMode ?? 'freehand'; const lassoPolygon = props.lassoPolygon ?? null; - const handleLassoComplete = props.onLassoComplete ?? (() => {}); + const noopLassoComplete = useCallback(() => {}, []); + const handleLassoComplete = props.onLassoComplete ?? noopLassoComplete; const { layers: lassoLayers } = useLassoLayer( lassoIsActive, handleLassoComplete, diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx index 26cf61bbc5..93110f661d 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx @@ -21,7 +21,6 @@ */ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { isEqual } from 'lodash'; -import { WebMercatorViewport } from '@math.gl/web-mercator'; import { Datasource, HandlerFunction, @@ -1022,8 +1021,6 @@ const DeckMulti = (props: DeckMultiProps) => { selectedFeatures, setSelectedFeatures, lassoPolygon, - anchorPosition, - setAnchorPosition, clearSelection, handleLassoToggle, handleLassoActivate, @@ -1064,28 +1061,7 @@ const DeckMulti = (props: DeckMultiProps) => { layerFeatureMap[name] = visibleFeatures; }); const result = filterMultiLayerFeaturesInLasso(layerFeatureMap, polygon); - // Debug: view lassoed data in browser console - console.group(`🔍 Lasso selected ${result.count} features`); - Object.entries(result.byLayer).forEach(([layer, feats]) => { - console.groupCollapsed(`${layer} (${feats.length})`); - console.table( - feats.map(f => ({ - geometryType: f.geometry?.type, - ...f.properties, - })), - ); - console.groupEnd(); - }); - console.groupEnd(); setSelectedFeatures(result.features); - - // Anchor the results bar near the end of the lasso - const lastCoord = polygon[polygon.length - 1]; - if (lastCoord) { - const wmv = new WebMercatorViewport({ ...viewport, width, height }); - const [px, py] = wmv.project(lastCoord); - setAnchorPosition({ x: px, y: py + 12 }); - } }, onActivate: () => { setMeasureState({ @@ -1257,7 +1233,6 @@ const DeckMulti = (props: DeckMultiProps) => { count={selectedFeatures.length} features={selectedFeatures} onClear={clearSelection} - anchorPosition={anchorPosition} /> )} {clickedFeature && ( diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/LassoDropdown.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/LassoDropdown.tsx new file mode 100644 index 0000000000..d301e43f57 --- /dev/null +++ b/superset-frontend/plugins/geoset-map-chart/src/components/LassoDropdown.tsx @@ -0,0 +1,225 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { memo } from 'react'; +import { styled } from '@superset-ui/core'; +import type { LassoDrawMode } from './LassoOverlay'; +import type { LassoLayer } from './MapControls'; + +export type LassoDropdownProps = { + hasMultipleLayers: boolean; + layers: LassoLayer[]; + activeLassoLayerId?: string; + onLayerSelect?: (layerId: string) => void; + drawMode: LassoDrawMode; + onDrawModeChange?: (mode: LassoDrawMode) => void; + onClose: () => void; +}; + +const DropdownPanel = styled.div( + ({ theme }) => ` + position: absolute; + top: calc(100% + 6px); + right: 0; + min-width: 200px; + background: ${theme.colorBgElevated}; + border: 1px solid ${theme.colorBorderSecondary}; + border-radius: 6px; + box-shadow: 0 4px 12px ${theme.colorText}1F; + overflow: hidden; +`, +); + +const DropdownHeader = styled.div( + ({ theme }) => ` + display: flex; + align-items: center; + justify-content: space-between; + padding: 8px 12px 6px; + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + color: ${theme.colorTextSecondary}; + border-bottom: 1px solid ${theme.colorBorderSecondary}; +`, +); + +const CloseButton = styled.button( + ({ theme }) => ` + display: flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + padding: 0; + background: transparent; + border: none; + cursor: pointer; + font-size: 14px; + line-height: 1; + color: ${theme.colorTextSecondary}; + + &:hover { + color: ${theme.colorText}; + } +`, +); + +const DropdownItem = styled.button( + ({ theme }) => ` + display: flex; + align-items: center; + gap: 8px; + width: 100%; + padding: 8px 12px; + background: transparent; + border: none; + cursor: pointer; + font-family: inherit; + font-size: 13px; + color: ${theme.colorText}; + text-align: left; + white-space: nowrap; + + &:hover { + background: ${theme.colorBgTextHover}; + } +`, +); + +const ModeToggleSection = styled.div( + ({ theme }) => ` + display: flex; + gap: 4px; + padding: 8px 12px; + border-top: 1px solid ${theme.colorBorderSecondary}; +`, +); + +const ModeButton = styled.button<{ $isActive?: boolean }>( + ({ theme, $isActive }) => ` + display: flex; + align-items: center; + gap: 4px; + flex: 1; + padding: 4px 8px; + background: ${$isActive ? theme.colorPrimaryBg : 'transparent'}; + border: none; + border-radius: 4px; + cursor: pointer; + font-family: inherit; + font-size: 11px; + color: ${$isActive ? theme.colorPrimary : theme.colorTextSecondary}; + white-space: nowrap; + + &:hover { + background: ${$isActive ? theme.colorPrimaryBgHover : theme.colorBgTextHover}; + } +`, +); + +const FreehandIcon = () => ( + + + +); + +const PolygonIcon = () => ( + + + + + + + +); + +const RadioIcon = ({ selected }: { selected: boolean }) => ( + + + {selected && } + +); + +const LassoDropdown = ({ + hasMultipleLayers, + layers, + activeLassoLayerId, + onLayerSelect, + drawMode, + onDrawModeChange, + onClose, +}: LassoDropdownProps) => ( + + + {hasMultipleLayers ? 'Select layer' : 'Lasso mode'} + + ✕ + + + {hasMultipleLayers && + layers.map(layer => { + const isSelected = layer.id === activeLassoLayerId; + return ( + onLayerSelect?.(layer.id)} + > + + {layer.name} + + ); + })} + + onDrawModeChange?.('freehand')} + > + Freehand + + onDrawModeChange?.('polygon')} + > + Point-to-point + + + +); + +export default memo(LassoDropdown); diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx index d2a55cb5a3..e25d97853f 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/LassoOverlay.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { EditableGeoJsonLayer, DrawPolygonByDraggingMode, @@ -27,6 +27,7 @@ import { PathLayer } from '@deck.gl/layers'; import { SolidPolygonLayer } from '@deck.gl/layers'; import { PathStyleExtension } from '@deck.gl/extensions'; import type { Coordinate } from '../utils/measureDistance'; +import { closeRing } from '../utils/lassoSelection'; export type LassoDrawMode = 'freehand' | 'polygon'; @@ -66,6 +67,10 @@ export function useLassoLayer( () => DRAW_MODES[drawMode], ); + // Use a ref so handleEdit stays stable regardless of caller memoization + const onPolygonCompleteRef = useRef(onPolygonComplete); + onPolygonCompleteRef.current = onPolygonComplete; + // Reset when lasso is activated or deactivated useEffect(() => { if (isActive) { @@ -89,10 +94,12 @@ export function useLassoLayer( updatedData.features[updatedData.features.length - 1]; const coords: number[][] = lastFeature.geometry.coordinates[0]; setMode(() => ViewMode); - onPolygonComplete(coords.map(c => [c[0], c[1]] as Coordinate)); + onPolygonCompleteRef.current( + coords.map(c => [c[0], c[1]] as Coordinate), + ); } }, - [onPolygonComplete], + [], ); // Editable layer for drawing phase @@ -123,13 +130,7 @@ export function useLassoLayer( const completedLayers = useMemo(() => { if (!completedPolygon || completedPolygon.length < 3) return []; - // Close the ring if needed - const ring = [...completedPolygon]; - const first = ring[0]; - const last = ring[ring.length - 1]; - if (first[0] !== last[0] || first[1] !== last[1]) { - ring.push(first); - } + const ring = closeRing(completedPolygon); return [ new SolidPolygonLayer({ diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx index 3d02b61d21..0d8577fef3 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx @@ -25,18 +25,15 @@ export interface LassoResultsBarProps { count: number; features: GeoJsonFeature[]; onClear: () => void; - anchorPosition?: { x: number; y: number } | null; } const CONTROL_MARGIN = 12; const TOP_OFFSET = 32 + CONTROL_MARGIN + 8; -const BarContainer = styled.div<{ $x?: number; $y?: number }>` +const BarContainer = styled.div` position: absolute; - ${({ $x, $y }) => - $x != null && $y != null - ? `left: ${$x}px; top: ${$y}px;` - : `left: ${CONTROL_MARGIN}px; top: ${TOP_OFFSET}px;`} + left: ${CONTROL_MARGIN}px; + top: ${TOP_OFFSET}px; z-index: 20; pointer-events: auto; `; @@ -174,7 +171,6 @@ const LassoResultsBar = ({ count, features, onClear, - anchorPosition, }: LassoResultsBarProps) => { const [isMenuOpen, setIsMenuOpen] = useState(false); const containerRef = useRef(null); @@ -196,11 +192,7 @@ const LassoResultsBar = ({ if (count === 0) return null; return ( - + {count} Items Selected { - exportToExcel(features).then(() => onClear()); + exportToExcel(features) + .then(() => onClear()) + .catch(err => { + // eslint-disable-next-line no-console + console.error('Excel export failed:', err); + }); setIsMenuOpen(false); }} > diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx index fe368f2aea..3db6605690 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/MapControls.tsx @@ -20,6 +20,7 @@ import { memo, useState, useRef, useEffect } from 'react'; import { styled } from '@superset-ui/core'; import type { LassoDrawMode } from './LassoOverlay'; +import LassoDropdown from './LassoDropdown'; export type LassoLayer = { id: string; name: string }; @@ -97,151 +98,6 @@ const ControlButton = styled.button<{ $isActive?: boolean }>( `, ); -const DropdownPanel = styled.div( - ({ theme }) => ` - position: absolute; - top: calc(100% + 6px); - right: 0; - min-width: 200px; - background: ${theme.colorBgElevated}; - border: 1px solid ${theme.colorBorderSecondary}; - border-radius: 6px; - box-shadow: 0 4px 12px ${theme.colorText}1F; - overflow: hidden; -`, -); - -const DropdownHeader = styled.div( - ({ theme }) => ` - display: flex; - align-items: center; - justify-content: space-between; - padding: 8px 12px 6px; - font-size: 11px; - font-weight: 600; - text-transform: uppercase; - color: ${theme.colorTextSecondary}; - border-bottom: 1px solid ${theme.colorBorderSecondary}; -`, -); - -const CloseButton = styled.button( - ({ theme }) => ` - display: flex; - align-items: center; - justify-content: center; - width: 18px; - height: 18px; - padding: 0; - background: transparent; - border: none; - cursor: pointer; - font-size: 14px; - line-height: 1; - color: ${theme.colorTextSecondary}; - - &:hover { - color: ${theme.colorText}; - } -`, -); - -const DropdownItem = styled.button( - ({ theme }) => ` - display: flex; - align-items: center; - gap: 8px; - width: 100%; - padding: 8px 12px; - background: transparent; - border: none; - cursor: pointer; - font-family: inherit; - font-size: 13px; - color: ${theme.colorText}; - text-align: left; - white-space: nowrap; - - &:hover { - background: ${theme.colorBgTextHover}; - } -`, -); - -const ModeToggleSection = styled.div( - ({ theme }) => ` - display: flex; - gap: 4px; - padding: 8px 12px; - border-top: 1px solid ${theme.colorBorderSecondary}; -`, -); - -const ModeButton = styled.button<{ $isActive?: boolean }>( - ({ theme, $isActive }) => ` - display: flex; - align-items: center; - gap: 4px; - flex: 1; - padding: 4px 8px; - background: ${$isActive ? theme.colorPrimaryBg : 'transparent'}; - border: none; - border-radius: 4px; - cursor: pointer; - font-family: inherit; - font-size: 11px; - color: ${$isActive ? theme.colorPrimary : theme.colorTextSecondary}; - white-space: nowrap; - - &:hover { - background: ${$isActive ? theme.colorPrimaryBgHover : theme.colorBgTextHover}; - } -`, -); - -const FreehandIcon = () => ( - - - -); - -const PolygonIcon = () => ( - - - - - - - -); - -const RadioIcon = ({ selected }: { selected: boolean }) => ( - - - {selected && } - -); - const HomeIcon = () => ( (null); const hasMultipleLayers = lassoLayers.length > 1; - // Close dropdown on outside click — activates lasso + // Close dropdown on outside click — only dismisses, does not activate lasso useEffect(() => { if (!isDropdownOpen) return undefined; const handleOutsideClick = (e: MouseEvent) => { @@ -324,20 +180,11 @@ const MapControls = ({ !containerRef.current.contains(e.target as Node) ) { setIsDropdownOpen(false); - // Multi-layer requires a layer selected; single-layer always activates - if (!hasMultipleLayers || activeLassoLayerId) { - onLassoActivate?.(); - } } }; document.addEventListener('mousedown', handleOutsideClick); return () => document.removeEventListener('mousedown', handleOutsideClick); - }, [ - isDropdownOpen, - hasMultipleLayers, - activeLassoLayerId, - onLassoActivate, - ]); + }, [isDropdownOpen]); const handleLassoButtonClick = () => { if (isLassoActive) { @@ -348,10 +195,6 @@ const MapControls = ({ } }; - const handleLayerSelect = (layerId: string) => { - onLassoLayerSelect?.(layerId); - }; - const handleCloseDropdown = () => { setIsDropdownOpen(false); if (!hasMultipleLayers || activeLassoLayerId) { @@ -390,41 +233,15 @@ const MapControls = ({ {isDropdownOpen && ( - - - {hasMultipleLayers ? 'Select layer' : 'Lasso mode'} - - ✕ - - - {hasMultipleLayers && - lassoLayers.map(layer => { - const isSelected = layer.id === activeLassoLayerId; - return ( - handleLayerSelect(layer.id)} - > - - {layer.name} - - ); - })} - - onLassoDrawModeChange?.('freehand')} - > - Freehand - - onLassoDrawModeChange?.('polygon')} - > - Point-to-point - - - + )} ); diff --git a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts index c6078c279b..a4d96e58a1 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts +++ b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts @@ -39,8 +39,6 @@ export type UseLassoSelectionResult = { selectedFeatures: GeoJsonFeature[]; setSelectedFeatures: (features: GeoJsonFeature[]) => void; lassoPolygon: Coordinate[] | null; - anchorPosition: { x: number; y: number } | null; - setAnchorPosition: (pos: { x: number; y: number } | null) => void; clearSelection: () => void; handleLassoToggle: () => void; handleLassoActivate: () => void; @@ -69,10 +67,6 @@ export function useLassoSelection( [], ); const [lassoPolygon, setLassoPolygon] = useState(null); - const [anchorPosition, setAnchorPosition] = useState<{ - x: number; - y: number; - } | null>(null); // Auto-select the first layer when available layers load and none is selected. const availableLayerIds = availableLayers.map(l => l.id).join(','); @@ -90,7 +84,6 @@ export function useLassoSelection( const clearSelection = useCallback(() => { setSelectedFeatures([]); setLassoPolygon(null); - setAnchorPosition(null); }, []); // Toggle lasso off — full reset including layer selection and results @@ -98,7 +91,6 @@ export function useLassoSelection( setLassoIsActive(false); setSelectedLassoLayerId(undefined); setSelectedFeatures([]); - setAnchorPosition(null); setLassoPolygon(null); }, []); @@ -128,7 +120,6 @@ export function useLassoSelection( setLassoIsActive(false); setSelectedFeatures([]); setLassoPolygon(null); - setAnchorPosition(null); } }; document.addEventListener('keydown', handleKeyDown); @@ -143,8 +134,6 @@ export function useLassoSelection( selectedFeatures, setSelectedFeatures, lassoPolygon, - anchorPosition, - setAnchorPosition, clearSelection, handleLassoToggle, handleLassoActivate, diff --git a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx index 099a241495..a61c25c886 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx @@ -38,7 +38,6 @@ import { QueryFormData, } from '@superset-ui/core'; import { Alert } from 'antd'; -import { WebMercatorViewport } from '@math.gl/web-mercator'; import Layer from '@deck.gl/core/dist/lib/layer'; import { useLassoSelection } from '../../hooks/useLassoSelection'; import { @@ -958,8 +957,6 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { selectedFeatures, setSelectedFeatures, lassoPolygon, - anchorPosition, - setAnchorPosition, clearSelection, handleLassoToggle, handleLassoActivate, @@ -990,24 +987,7 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { : allFeatures; const selected = filterFeaturesInLasso(visibleFeatures, polygon); - // Debug: view lassoed data in browser console - console.group(`🔍 Lasso selected ${selected.length} features`); - console.table( - selected.map(f => ({ - geometryType: f.geometry?.type, - ...f.properties, - })), - ); - console.groupEnd(); setSelectedFeatures(selected); - - // Anchor the results bar near the end of the lasso - const lastCoord = polygon[polygon.length - 1]; - if (lastCoord) { - const wmv = new WebMercatorViewport({ ...viewport, width, height }); - const [px, py] = wmv.project(lastCoord); - setAnchorPosition({ x: px, y: py + 12 }); - } }, onActivate: () => { setMeasureState({ @@ -1313,7 +1293,6 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { count={selectedFeatures.length} features={selectedFeatures} onClear={clearSelection} - anchorPosition={anchorPosition} /> )} { it('returns correct initial state', () => { const { result } = renderHook(() => useLassoSelection()); expect(result.current.lassoIsActive).toBe(false); expect(result.current.lassoDrawMode).toBe('freehand'); - expect(result.current.selectedLassoLayerIds).toEqual([]); + expect(result.current.selectedLassoLayerId).toBeUndefined(); }); it('activates lasso on handleLassoActivate', () => { @@ -22,7 +23,7 @@ describe('useLassoSelection', () => { expect(onActivate).toHaveBeenCalledTimes(1); }); - it('deactivates and clears layers on handleLassoToggle', () => { + it('deactivates and clears layer on handleLassoToggle', () => { const { result } = renderHook(() => useLassoSelection({ availableLayers: [ @@ -35,15 +36,15 @@ describe('useLassoSelection', () => { // Activate and verify layer is auto-selected act(() => result.current.handleLassoActivate()); expect(result.current.lassoIsActive).toBe(true); - expect(result.current.selectedLassoLayerIds).toEqual(['1']); + expect(result.current.selectedLassoLayerId).toBe('1'); // Toggle off — should clear everything act(() => result.current.handleLassoToggle()); expect(result.current.lassoIsActive).toBe(false); - expect(result.current.selectedLassoLayerIds).toEqual([]); + expect(result.current.selectedLassoLayerId).toBeUndefined(); }); - it('deactivates without clearing layers on deactivateLasso', () => { + it('deactivates without clearing layer on deactivateLasso', () => { const { result } = renderHook(() => useLassoSelection({ availableLayers: [{ id: '1', name: 'Layer 1' }], @@ -51,12 +52,12 @@ describe('useLassoSelection', () => { ); act(() => result.current.handleLassoActivate()); - expect(result.current.selectedLassoLayerIds).toEqual(['1']); + expect(result.current.selectedLassoLayerId).toBe('1'); - // Soft deactivation — layers preserved + // Soft deactivation — layer preserved act(() => result.current.deactivateLasso()); expect(result.current.lassoIsActive).toBe(false); - expect(result.current.selectedLassoLayerIds).toEqual(['1']); + expect(result.current.selectedLassoLayerId).toBe('1'); }); it('changes draw mode via setLassoDrawMode', () => { @@ -65,18 +66,14 @@ describe('useLassoSelection', () => { expect(result.current.lassoDrawMode).toBe('polygon'); }); - it('toggles layer ids on handleLassoLayerToggle', () => { + it('selects a layer via handleLassoLayerSelect', () => { const { result } = renderHook(() => useLassoSelection()); - act(() => result.current.handleLassoLayerToggle('a')); - expect(result.current.selectedLassoLayerIds).toEqual(['a']); + act(() => result.current.handleLassoLayerSelect('a')); + expect(result.current.selectedLassoLayerId).toBe('a'); - act(() => result.current.handleLassoLayerToggle('b')); - expect(result.current.selectedLassoLayerIds).toEqual(['a', 'b']); - - // Toggle 'a' off - act(() => result.current.handleLassoLayerToggle('a')); - expect(result.current.selectedLassoLayerIds).toEqual(['b']); + act(() => result.current.handleLassoLayerSelect('b')); + expect(result.current.selectedLassoLayerId).toBe('b'); }); it('auto-selects first layer when availableLayers provided', () => { @@ -88,19 +85,19 @@ describe('useLassoSelection', () => { ], }), ); - expect(result.current.selectedLassoLayerIds).toEqual(['x']); + expect(result.current.selectedLassoLayerId).toBe('x'); }); - it('does not auto-select when layers are already selected', () => { + it('does not auto-select when a layer is already selected', () => { const { result } = renderHook(() => useLassoSelection({ availableLayers: [{ id: 'x', name: 'X' }], }), ); - // Manually toggle to 'y', then re-render with new available layers - act(() => result.current.handleLassoLayerToggle('y')); - expect(result.current.selectedLassoLayerIds).toContain('y'); + // Manually select 'y', then verify auto-select did not override + act(() => result.current.handleLassoLayerSelect('y')); + expect(result.current.selectedLassoLayerId).toBe('y'); }); it('calls onPolygonComplete when handleLassoComplete is called', () => { @@ -108,7 +105,7 @@ describe('useLassoSelection', () => { const { result } = renderHook(() => useLassoSelection({ onPolygonComplete }), ); - const polygon = [ + const polygon: Coordinate[] = [ [0, 0], [1, 0], [1, 1], @@ -168,7 +165,7 @@ describe('useLassoSelection', () => { rerender({ cb: second }); - const polygon = [[0, 0]]; + const polygon: Coordinate[] = [[0, 0]]; act(() => result.current.handleLassoComplete(polygon)); expect(first).not.toHaveBeenCalled(); From 45d9ffd2173d20f039d1468a4affee7d92bd2269 Mon Sep 17 00:00:00 2001 From: lhawkins Date: Wed, 25 Mar 2026 16:35:38 -0400 Subject: [PATCH 13/37] fix: Improve lasso UX with dashed outlines, activation flow, and anchored results - Add dashed stroke styling to lasso polygon and guide lines - Delay draw mode activation to prevent dropdown close click from placing a vertex - Reset drawing state when results are cleared for seamless re-lasso - Activate lasso on outside click when a layer is already selected - Anchor results bar near the end of the drawn polygon instead of fixed position - Add defaultLayerName option to auto-select preferred layer - Preserve selected layer when toggling lasso off - Rename "Freehand" mode label to "Click-and-drag" - Remove unused @turf/boolean-within dependency Co-Authored-By: Claude Opus 4.6 (1M context) --- superset-frontend/package-lock.json | 1 - .../src/GeoSetMultiMap/Multi.tsx | 13 +++++ .../src/components/LassoDropdown.tsx | 2 +- .../src/components/LassoOverlay.tsx | 51 ++++++++++++++++++- .../src/components/LassoResultsBar.tsx | 16 ++++-- .../src/components/MapControls.tsx | 7 ++- .../src/hooks/useLassoSelection.ts | 27 ++++++++-- .../src/layers/GeoSetLayer/GeoSetLayer.tsx | 12 +++++ 8 files changed, 114 insertions(+), 15 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index b8133f5a9c..c4901073bf 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -59617,7 +59617,6 @@ "@math.gl/web-mercator": "^4.1.0", "@turf/area": "^7.2.0", "@turf/boolean-point-in-polygon": "^7.2.0", - "@turf/boolean-within": "^7.2.0", "@turf/centroid": "^7.2.0", "@turf/helpers": "^7.2.0", "@turf/intersect": "^7.2.0", diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx index 93110f661d..c91ea10f33 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx @@ -21,6 +21,7 @@ */ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { isEqual } from 'lodash'; +import { WebMercatorViewport } from '@math.gl/web-mercator'; import { Datasource, HandlerFunction, @@ -1021,6 +1022,8 @@ const DeckMulti = (props: DeckMultiProps) => { selectedFeatures, setSelectedFeatures, lassoPolygon, + anchorPosition, + setAnchorPosition, clearSelection, handleLassoToggle, handleLassoActivate, @@ -1029,6 +1032,7 @@ const DeckMulti = (props: DeckMultiProps) => { deactivateLasso, } = useLassoSelection({ availableLayers: lassoLayers, + defaultLayerName: 'All Program Offices', onPolygonComplete: polygon => { const layerFeatureMap: Record = {}; sortedLayers.forEach(entry => { @@ -1062,6 +1066,14 @@ const DeckMulti = (props: DeckMultiProps) => { }); const result = filterMultiLayerFeaturesInLasso(layerFeatureMap, polygon); setSelectedFeatures(result.features); + + // Anchor the results bar near the end of the lasso + const lastCoord = polygon[polygon.length - 1]; + if (lastCoord) { + const wmv = new WebMercatorViewport({ ...viewport, width, height }); + const [px, py] = wmv.project(lastCoord); + setAnchorPosition({ x: px, y: py + 12 }); + } }, onActivate: () => { setMeasureState({ @@ -1233,6 +1245,7 @@ const DeckMulti = (props: DeckMultiProps) => { count={selectedFeatures.length} features={selectedFeatures} onClear={clearSelection} + anchorPosition={anchorPosition} /> )} {clickedFeature && ( diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/LassoDropdown.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/LassoDropdown.tsx index d301e43f57..d975cd5811 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/LassoDropdown.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/LassoDropdown.tsx @@ -210,7 +210,7 @@ const LassoDropdown = ({ $isActive={drawMode === 'freehand'} onClick={() => onDrawModeChange?.('freehand')} > - Freehand + Click-and-drag { if (isActive) { setData(EMPTY_FEATURE_COLLECTION); - setMode(() => DRAW_MODES[drawMode]); + setMode(() => ViewMode); + const timer = setTimeout(() => { + setMode(() => DRAW_MODES[drawMode]); + }, 300); + return () => clearTimeout(timer); } + return undefined; }, [isActive]); // eslint-disable-line react-hooks/exhaustive-deps + // Reset drawing state when completed polygon is cleared (user dismissed results) + // so the editable layer returns to draw mode for a new lasso + useEffect(() => { + if (isActive && !completedPolygon) { + setData(EMPTY_FEATURE_COLLECTION); + setMode(() => DRAW_MODES[drawMode]); + } + }, [completedPolygon]); // eslint-disable-line react-hooks/exhaustive-deps + // Switch draw mode while active (without resetting polygon data) useEffect(() => { if (isActive) { @@ -121,6 +136,38 @@ export function useLassoLayer( getTentativeFillColor: [66, 133, 244, 15], getTentativeLineColor: [40, 40, 40, 200], + // Dashed outline on both the main geojson and guides (tentative) sub-layers + _subLayerProps: { + geojson: { + _subLayerProps: { + linestrings: { + getDashArray: [8, 4], + dashJustified: true, + extensions: [new PathStyleExtension({ dash: true })], + }, + 'polygons-stroke': { + getDashArray: [8, 4], + dashJustified: true, + extensions: [new PathStyleExtension({ dash: true })], + }, + }, + }, + guides: { + _subLayerProps: { + linestrings: { + getDashArray: [8, 4], + dashJustified: true, + extensions: [new PathStyleExtension({ dash: true })], + }, + 'polygons-stroke': { + getDashArray: [8, 4], + dashJustified: true, + extensions: [new PathStyleExtension({ dash: true })], + }, + }, + }, + }, + pickable: true, }), ]; diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx index 0d8577fef3..84b3acaa6d 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx @@ -25,15 +25,18 @@ export interface LassoResultsBarProps { count: number; features: GeoJsonFeature[]; onClear: () => void; + anchorPosition?: { x: number; y: number } | null; } const CONTROL_MARGIN = 12; const TOP_OFFSET = 32 + CONTROL_MARGIN + 8; -const BarContainer = styled.div` +const BarContainer = styled.div<{ $anchorX?: number; $anchorY?: number }>` position: absolute; - left: ${CONTROL_MARGIN}px; - top: ${TOP_OFFSET}px; + ${({ $anchorX, $anchorY }) => + $anchorX != null && $anchorY != null + ? `left: ${$anchorX}px; top: ${$anchorY}px;` + : `left: ${CONTROL_MARGIN}px; top: ${TOP_OFFSET}px;`} z-index: 20; pointer-events: auto; `; @@ -171,6 +174,7 @@ const LassoResultsBar = ({ count, features, onClear, + anchorPosition, }: LassoResultsBarProps) => { const [isMenuOpen, setIsMenuOpen] = useState(false); const containerRef = useRef(null); @@ -192,7 +196,11 @@ const LassoResultsBar = ({ if (count === 0) return null; return ( - + {count} Items Selected (null); const hasMultipleLayers = lassoLayers.length > 1; - // Close dropdown on outside click — only dismisses, does not activate lasso + // Close dropdown on outside click — activates lasso if a layer is selected useEffect(() => { if (!isDropdownOpen) return undefined; const handleOutsideClick = (e: MouseEvent) => { @@ -180,11 +180,14 @@ const MapControls = ({ !containerRef.current.contains(e.target as Node) ) { setIsDropdownOpen(false); + if (!hasMultipleLayers || activeLassoLayerId) { + onLassoActivate?.(); + } } }; document.addEventListener('mousedown', handleOutsideClick); return () => document.removeEventListener('mousedown', handleOutsideClick); - }, [isDropdownOpen]); + }, [isDropdownOpen, hasMultipleLayers, activeLassoLayerId, onLassoActivate]); const handleLassoButtonClick = () => { if (isLassoActive) { diff --git a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts index a4d96e58a1..825d2c6988 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts +++ b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts @@ -25,6 +25,8 @@ import type { GeoJsonFeature } from '../types'; export type UseLassoSelectionOptions = { /** Available layers for lasso selection. Omit or pass empty for single-layer. */ availableLayers?: LassoLayer[]; + /** Preferred default layer name. Falls back to first layer if not found. */ + defaultLayerName?: string; /** Called when lasso polygon drawing completes. */ onPolygonComplete?: (polygon: Coordinate[]) => void; /** Called when lasso is activated (useful for deactivating other modes like ruler). */ @@ -39,6 +41,8 @@ export type UseLassoSelectionResult = { selectedFeatures: GeoJsonFeature[]; setSelectedFeatures: (features: GeoJsonFeature[]) => void; lassoPolygon: Coordinate[] | null; + anchorPosition: { x: number; y: number } | null; + setAnchorPosition: (pos: { x: number; y: number } | null) => void; clearSelection: () => void; handleLassoToggle: () => void; handleLassoActivate: () => void; @@ -50,7 +54,7 @@ export type UseLassoSelectionResult = { export function useLassoSelection( options: UseLassoSelectionOptions = {}, ): UseLassoSelectionResult { - const { availableLayers = [] } = options; + const { availableLayers = [], defaultLayerName } = options; // Use refs for callbacks to avoid stale closures without re-triggering effects const onPolygonCompleteRef = useRef(options.onPolygonComplete); @@ -67,12 +71,21 @@ export function useLassoSelection( [], ); const [lassoPolygon, setLassoPolygon] = useState(null); + const [anchorPosition, setAnchorPosition] = useState<{ + x: number; + y: number; + } | null>(null); - // Auto-select the first layer when available layers load and none is selected. + // Auto-select the preferred layer (by name), falling back to first layer. const availableLayerIds = availableLayers.map(l => l.id).join(','); useEffect(() => { if (availableLayers.length > 0 && !selectedLassoLayerId) { - setSelectedLassoLayerId(availableLayers[0].id); + const preferred = defaultLayerName + ? availableLayers.find( + l => l.name.toLowerCase() === defaultLayerName.toLowerCase(), + ) + : undefined; + setSelectedLassoLayerId(preferred?.id ?? availableLayers[0].id); } }, [availableLayerIds]); // eslint-disable-line react-hooks/exhaustive-deps @@ -84,14 +97,15 @@ export function useLassoSelection( const clearSelection = useCallback(() => { setSelectedFeatures([]); setLassoPolygon(null); + setAnchorPosition(null); }, []); - // Toggle lasso off — full reset including layer selection and results + // Toggle lasso off — clear results but preserve the selected layer const handleLassoToggle = useCallback(() => { setLassoIsActive(false); - setSelectedLassoLayerId(undefined); setSelectedFeatures([]); setLassoPolygon(null); + setAnchorPosition(null); }, []); // Activate lasso drawing and notify parent (e.g. to deactivate ruler) @@ -120,6 +134,7 @@ export function useLassoSelection( setLassoIsActive(false); setSelectedFeatures([]); setLassoPolygon(null); + setAnchorPosition(null); } }; document.addEventListener('keydown', handleKeyDown); @@ -134,6 +149,8 @@ export function useLassoSelection( selectedFeatures, setSelectedFeatures, lassoPolygon, + anchorPosition, + setAnchorPosition, clearSelection, handleLassoToggle, handleLassoActivate, diff --git a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx index a61c25c886..9021f744e7 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/layers/GeoSetLayer/GeoSetLayer.tsx @@ -26,6 +26,7 @@ import { ScatterplotLayer, } from '@deck.gl/layers'; import { PathStyleExtension } from '@deck.gl/extensions'; +import { WebMercatorViewport } from '@math.gl/web-mercator'; // ignoring the eslint error below since typescript prefers 'geojson' to '@types/geojson' // eslint-disable-next-line import/no-unresolved import { Feature, Geometry, GeoJsonProperties } from 'geojson'; @@ -957,6 +958,8 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { selectedFeatures, setSelectedFeatures, lassoPolygon, + anchorPosition, + setAnchorPosition, clearSelection, handleLassoToggle, handleLassoActivate, @@ -988,6 +991,14 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { const selected = filterFeaturesInLasso(visibleFeatures, polygon); setSelectedFeatures(selected); + + // Anchor the results bar near the end of the lasso + const lastCoord = polygon[polygon.length - 1]; + if (lastCoord) { + const wmv = new WebMercatorViewport({ ...viewport, width, height }); + const [px, py] = wmv.project(lastCoord); + setAnchorPosition({ x: px, y: py + 12 }); + } }, onActivate: () => { setMeasureState({ @@ -1293,6 +1304,7 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => { count={selectedFeatures.length} features={selectedFeatures} onClear={clearSelection} + anchorPosition={anchorPosition} /> )} Date: Wed, 25 Mar 2026 16:36:14 -0400 Subject: [PATCH 14/37] docs: Add LassoDropdown to Development Guide key utilities table Co-Authored-By: Claude Opus 4.6 (1M context) --- wiki/Development-Guide.md | 1 + 1 file changed, 1 insertion(+) diff --git a/wiki/Development-Guide.md b/wiki/Development-Guide.md index a479f82999..f6b844f41d 100644 --- a/wiki/Development-Guide.md +++ b/wiki/Development-Guide.md @@ -120,6 +120,7 @@ Each phase checks a staleness flag before proceeding. When the user changes a fi | `utils/liveViewportStore.ts` | Module-level store for live viewport state (bypasses Redux to avoid "Altered" chart state) | | `components/MultiLegend.tsx` | Drag-and-drop multi-layer legend with toggle/isolate | | `components/MapControls.tsx` | Zoom controls, measurement tool, and lasso select tool | +| `components/LassoDropdown.tsx` | Layer picker and draw-mode toggle dropdown for the lasso tool | | `components/LassoOverlay.tsx` | Lasso drawing layers (freehand and point-to-point polygon modes) via `useLassoLayer` hook | | `components/LassoResultsBar.tsx` | Selection count bar with CSV/Excel export menu | | `hooks/useLassoSelection.ts` | Shared React hook managing lasso state, polygon completion, and layer selection | From 4c8315d12a408ed1337d753a31a23d7c1c6eeead Mon Sep 17 00:00:00 2001 From: lhawkins Date: Wed, 25 Mar 2026 17:01:10 -0400 Subject: [PATCH 15/37] feat: Highlight lasso-selected features and dim unselected layers Add a GeoJsonLayer overlay in DeckGLContainer that renders lasso-selected features with their original colors on top of dimmed data layers (opacity 0.15). Both Multi and GeoSetLayer pass selectedFeatures to the container. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../geoset-map-chart/src/DeckGLContainer.tsx | 46 +++++++++++++++++-- .../src/GeoSetMultiMap/Multi.tsx | 1 + .../src/layers/GeoSetLayer/GeoSetLayer.tsx | 1 + 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx b/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx index 140f0ef7d4..44379b1b40 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/DeckGLContainer.tsx @@ -34,6 +34,7 @@ import { import { StaticMap, MapRef } from 'react-map-gl'; import DeckGL from '@deck.gl/react'; import type { Deck, Layer } from '@deck.gl/core'; +import { GeoJsonLayer } from '@deck.gl/layers'; import { JsonObject, JsonValue, styled } from '@superset-ui/core'; import Tooltip, { TooltipProps } from './components/Tooltip'; import 'mapbox-gl/dist/mapbox-gl.css'; @@ -42,7 +43,7 @@ import { isValidViewport, toNumericViewport, } from './utils/fitViewport'; -import { LayerState } from './types'; +import { GeoJsonFeature, LayerState } from './types'; import { MeasureState, useMeasureLayers } from './components/MeasureOverlay'; import { LASSO_CURSOR, @@ -74,6 +75,7 @@ export type DeckGLContainerProps = { lassoDrawMode?: LassoDrawMode; lassoPolygon?: Coordinate[] | null; onLassoComplete?: (polygon: Coordinate[]) => void; + selectedFeatures?: GeoJsonFeature[]; onEmptyClick?: () => void; }; @@ -391,16 +393,50 @@ export const DeckGLContainer = memo( lassoPolygon, ); + const selectedFeaturesArr = props.selectedFeatures ?? []; + const hasSelection = selectedFeaturesArr.length > 0; + + // Build a highlight layer from lasso-selected features + const highlightLayer = useMemo(() => { + if (!hasSelection) return []; + return [ + new GeoJsonLayer({ + id: 'lasso-highlight', + data: { + type: 'FeatureCollection' as const, + features: selectedFeaturesArr, + }, + getFillColor: (f: any) => f.color ?? f.properties?.color ?? [255, 200, 0, 200], + getLineColor: (f: any) => + f.strokeColor ?? f.properties?.strokeColor ?? [40, 40, 40, 220], + getPointRadius: (f: any) => f.sizeValue ?? 4, + pointRadiusMinPixels: 4, + lineWidthMinPixels: 1, + pickable: false, + }), + ]; + }, [hasSelection, selectedFeaturesArr]); + const allLayers = useMemo(() => { if (!layerStates || layerStates.length === 0) { - return [...measureLayers, ...lassoLayers] as Layer[]; + return [...measureLayers, ...highlightLayer, ...lassoLayers] as Layer[]; } - const layers = layerStates + let layers = layerStates .map(ls => ls?.layer) .filter(Boolean) as Layer[]; - return [...layers, ...measureLayers, ...lassoLayers] as Layer[]; - }, [layerStates, measureLayers, lassoLayers]); + // Dim all data layers when there's an active lasso selection + if (hasSelection) { + layers = layers.map(l => l.clone({ opacity: 0.15 })); + } + + return [ + ...layers, + ...highlightLayer, + ...measureLayers, + ...lassoLayers, + ] as Layer[]; + }, [layerStates, measureLayers, lassoLayers, highlightLayer, hasSelection]); useEffect(() => { if (!props.layerStates) return; diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx index c91ea10f33..c0b7df3c3d 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx @@ -1216,6 +1216,7 @@ const DeckMulti = (props: DeckMultiProps) => { lassoDrawMode={lassoDrawMode} lassoPolygon={lassoPolygon} onLassoComplete={handleLassoComplete} + selectedFeatures={selectedFeatures} onEmptyClick={handleClosePopup} /> { lassoDrawMode={lassoDrawMode} lassoPolygon={lassoPolygon} onLassoComplete={handleLassoComplete} + selectedFeatures={selectedFeatures} onEmptyClick={handleClosePopup} /> Date: Thu, 26 Mar 2026 12:46:07 -0400 Subject: [PATCH 16/37] feat: Add per-layer lasso-selectable option and improve lasso geometry support Add a configurable "Lasso Selectable" toggle to the layer settings popover, letting users control which layers appear in the lasso tool's dropdown. Also adds LineString/MultiLineString geometry support to lasso selection, prevents feature popups while lasso is active, removes the disabled "Download as image" placeholder, and simplifies default layer selection by removing the hardcoded defaultLayerName preference. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/GeoSetMultiMap/Multi.tsx | 26 +++++++++----- .../src/GeoSetMultiMap/multiUtils.ts | 3 ++ .../src/components/LassoResultsBar.tsx | 3 -- .../src/hooks/useLassoSelection.ts | 13 ++----- .../src/utils/lassoSelection.ts | 17 +++++++-- .../test/GeoSetMultiMap/multiUtils.test.ts | 33 +++++++++++++++++ .../controls/DeckSlicesControl/index.tsx | 35 ++++++++++++++++++- wiki/Development-Guide.md | 2 +- wiki/GeoSet-Multi-Map.md | 1 + 9 files changed, 106 insertions(+), 27 deletions(-) diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx index c0b7df3c3d..2c17d893e0 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx @@ -140,6 +140,7 @@ type SubsliceLayerEntry = { zoomSliderOptions: { minZoom: number; maxZoom: number }; initiallyHidden: boolean; // Whether this layer starts hidden lazyLoading: boolean; // Whether this layer is configured for lazy loading + lassoSelectable: boolean; // Whether this layer appears in the lasso dropdown }; interface ClickedFeatureWithColumns extends ClickedFeatureInfo { @@ -150,6 +151,7 @@ const DeckMulti = (props: DeckMultiProps) => { const containerRef = useRef(null); // Ref to track measure state for use in callbacks without creating dependencies const measureActiveRef = useRef(false); + const lassoIsActiveRef = useRef(false); // Generation counter to cancel stale lazy-loading chains const loadGenerationRef = useRef(0); // Store initial autozoom viewport to prevent reset on category toggle @@ -172,7 +174,7 @@ const DeckMulti = (props: DeckMultiProps) => { // Don't show popup when measurement mode is active (uses ref to avoid dependency issues) const handleFeatureClick = useCallback( (info: any, featureInfoColumnNames?: string[]) => { - if (measureActiveRef.current) return; + if (measureActiveRef.current || lassoIsActiveRef.current) return; if (info?.object?.properties) { setClickedFeature({ properties: info.object.properties, @@ -504,6 +506,7 @@ const DeckMulti = (props: DeckMultiProps) => { zoomSliderOptions: newLayerStateOptions, initiallyHidden: sliceInitiallyHidden, lazyLoading: sliceLazyLoading, + lassoSelectable: sliceConfig?.lassoSelectable ?? true, }; }); }) @@ -632,6 +635,7 @@ const DeckMulti = (props: DeckMultiProps) => { ...layer, autozoom: resolveLayerAutozoom(config), lazyLoading: config?.lazyLoading ?? false, + lassoSelectable: config?.lassoSelectable ?? true, }; }); }); @@ -883,15 +887,17 @@ const DeckMulti = (props: DeckMultiProps) => { [sortedLayers, layerVisibility], ); - // Layer list for lasso layer picker dropdown + // Layer list for lasso layer picker dropdown — only lasso-selectable layers const lassoLayers = useMemo( () => - sortedLayers.map(entry => ({ - id: String(entry.sliceId), - name: - (entry.legendEntry.sliceName as string | undefined) || - entry.legendEntry.legendName, - })), + sortedLayers + .filter(entry => entry.lassoSelectable !== false) + .map(entry => ({ + id: String(entry.sliceId), + name: + (entry.legendEntry.sliceName as string | undefined) || + entry.legendEntry.legendName, + })), [sortedLayers], ); @@ -1032,7 +1038,6 @@ const DeckMulti = (props: DeckMultiProps) => { deactivateLasso, } = useLassoSelection({ availableLayers: lassoLayers, - defaultLayerName: 'All Program Offices', onPolygonComplete: polygon => { const layerFeatureMap: Record = {}; sortedLayers.forEach(entry => { @@ -1085,6 +1090,9 @@ const DeckMulti = (props: DeckMultiProps) => { }, }); + // Keep ref in sync with lasso state for use in memoized callbacks + lassoIsActiveRef.current = lassoIsActive; + const handleRulerToggle = useCallback(() => { setMeasureState(prev => { if (prev.isActive) { diff --git a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/multiUtils.ts b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/multiUtils.ts index 789461237a..a1833f7749 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/multiUtils.ts +++ b/superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/multiUtils.ts @@ -23,6 +23,7 @@ export interface DeckSliceConfig { legendCollapsed: boolean; initiallyHidden: boolean; lazyLoading: boolean; + lassoSelectable: boolean; } /** Resolve effective autozoom for a slice: disabled when lazy loading is on */ @@ -42,6 +43,7 @@ export const normalizeDeckSlices = ( legendCollapsed: false, initiallyHidden: false, lazyLoading: false, + lassoSelectable: true, } : { sliceId: item.sliceId, @@ -49,6 +51,7 @@ export const normalizeDeckSlices = ( legendCollapsed: item.legendCollapsed ?? false, initiallyHidden: item.initiallyHidden ?? false, lazyLoading: item.lazyLoading ?? false, + lassoSelectable: item.lassoSelectable ?? true, }, ) ?? []; diff --git a/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx b/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx index 84b3acaa6d..fff205b938 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx +++ b/superset-frontend/plugins/geoset-map-chart/src/components/LassoResultsBar.tsx @@ -239,9 +239,6 @@ const LassoResultsBar = ({ > Export to Excel - - Download as image - )} diff --git a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts index 825d2c6988..aec5fc517e 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts +++ b/superset-frontend/plugins/geoset-map-chart/src/hooks/useLassoSelection.ts @@ -25,8 +25,6 @@ import type { GeoJsonFeature } from '../types'; export type UseLassoSelectionOptions = { /** Available layers for lasso selection. Omit or pass empty for single-layer. */ availableLayers?: LassoLayer[]; - /** Preferred default layer name. Falls back to first layer if not found. */ - defaultLayerName?: string; /** Called when lasso polygon drawing completes. */ onPolygonComplete?: (polygon: Coordinate[]) => void; /** Called when lasso is activated (useful for deactivating other modes like ruler). */ @@ -54,7 +52,7 @@ export type UseLassoSelectionResult = { export function useLassoSelection( options: UseLassoSelectionOptions = {}, ): UseLassoSelectionResult { - const { availableLayers = [], defaultLayerName } = options; + const { availableLayers = [] } = options; // Use refs for callbacks to avoid stale closures without re-triggering effects const onPolygonCompleteRef = useRef(options.onPolygonComplete); @@ -76,16 +74,11 @@ export function useLassoSelection( y: number; } | null>(null); - // Auto-select the preferred layer (by name), falling back to first layer. + // Auto-select the first available layer when none is selected. const availableLayerIds = availableLayers.map(l => l.id).join(','); useEffect(() => { if (availableLayers.length > 0 && !selectedLassoLayerId) { - const preferred = defaultLayerName - ? availableLayers.find( - l => l.name.toLowerCase() === defaultLayerName.toLowerCase(), - ) - : undefined; - setSelectedLassoLayerId(preferred?.id ?? availableLayers[0].id); + setSelectedLassoLayerId(availableLayers[0].id); } }, [availableLayerIds]); // eslint-disable-line react-hooks/exhaustive-deps diff --git a/superset-frontend/plugins/geoset-map-chart/src/utils/lassoSelection.ts b/superset-frontend/plugins/geoset-map-chart/src/utils/lassoSelection.ts index dc2ba74b1c..3131781c97 100644 --- a/superset-frontend/plugins/geoset-map-chart/src/utils/lassoSelection.ts +++ b/superset-frontend/plugins/geoset-map-chart/src/utils/lassoSelection.ts @@ -74,8 +74,8 @@ export function closeRing(coords: Coordinate[]): Coordinate[] { * Test whether a feature intersects the lasso polygon. * * - Point / MultiPoint: direct point-in-polygon test (fast) - * - Polygon / LineString / etc.: boolean intersects test — - * selected if any part of the geometry overlaps the lasso area + * - Polygon / MultiPolygon: selected if >= 50% area overlap + * - LineString / MultiLineString: selected if any vertex is inside */ function isFeatureInLasso( feature: GeoJsonFeature, @@ -107,8 +107,19 @@ function isFeatureInLasso( if (!overlap) return false; return area(overlap) / featureArea >= POLYGON_OVERLAP_THRESHOLD; } + case 'LineString': { + // Selected if any vertex of the line is inside the lasso + return (geometry.coordinates as [number, number][]).some(pt => + booleanPointInPolygon(turfPoint(pt), lassoPoly), + ); + } + case 'MultiLineString': { + return (geometry.coordinates as [number, number][][]).some(line => + line.some(pt => booleanPointInPolygon(turfPoint(pt), lassoPoly)), + ); + } default: - // LineString, MultiLineString, GeometryCollection — skip + // GeometryCollection, etc. — skip return false; } } catch { diff --git a/superset-frontend/plugins/geoset-map-chart/test/GeoSetMultiMap/multiUtils.test.ts b/superset-frontend/plugins/geoset-map-chart/test/GeoSetMultiMap/multiUtils.test.ts index 1b6c06cc8f..6cf3524705 100644 --- a/superset-frontend/plugins/geoset-map-chart/test/GeoSetMultiMap/multiUtils.test.ts +++ b/superset-frontend/plugins/geoset-map-chart/test/GeoSetMultiMap/multiUtils.test.ts @@ -34,6 +34,7 @@ const makeConfig = ( legendCollapsed: false, initiallyHidden: false, lazyLoading: false, + lassoSelectable: true, ...overrides, }); @@ -46,6 +47,7 @@ describe('resolveLayerAutozoom', () => { legendCollapsed: false, initiallyHidden: false, lazyLoading: true, + lassoSelectable: true, }), ).toBe(false); }); @@ -58,6 +60,7 @@ describe('resolveLayerAutozoom', () => { legendCollapsed: false, initiallyHidden: false, lazyLoading: true, + lassoSelectable: true, }), ).toBe(false); }); @@ -70,6 +73,7 @@ describe('resolveLayerAutozoom', () => { legendCollapsed: false, initiallyHidden: false, lazyLoading: false, + lassoSelectable: true, }), ).toBe(true); }); @@ -82,6 +86,7 @@ describe('resolveLayerAutozoom', () => { legendCollapsed: false, initiallyHidden: false, lazyLoading: false, + lassoSelectable: true, }), ).toBe(false); }); @@ -107,6 +112,7 @@ describe('normalizeDeckSlices', () => { legendCollapsed: false, initiallyHidden: false, lazyLoading: true, + lassoSelectable: true, }, ]); expect(result[0].lazyLoading).toBe(true); @@ -120,6 +126,7 @@ describe('normalizeDeckSlices', () => { legendCollapsed: false, initiallyHidden: false, lazyLoading: true, + lassoSelectable: true, }, ]); expect(resolveLayerAutozoom(result[0])).toBe(false); @@ -128,6 +135,32 @@ describe('normalizeDeckSlices', () => { it('returns empty array when input is undefined', () => { expect(normalizeDeckSlices(undefined)).toEqual([]); }); + + it('sets lassoSelectable to true by default for legacy number entries', () => { + const result = normalizeDeckSlices([1, 2]); + result.forEach(slice => { + expect(slice.lassoSelectable).toBe(true); + }); + }); + + it('preserves lassoSelectable: false from config objects', () => { + const result = normalizeDeckSlices([ + makeConfig(1, { lassoSelectable: false }), + ]); + expect(result[0].lassoSelectable).toBe(false); + }); + + it('defaults lassoSelectable to true when field is missing from config object', () => { + const configWithoutLasso = { + sliceId: 1, + autozoom: true, + legendCollapsed: false, + initiallyHidden: false, + lazyLoading: false, + } as any; + const result = normalizeDeckSlices([configWithoutLasso]); + expect(result[0].lassoSelectable).toBe(true); + }); }); describe('loadLayersOrchestrated', () => { diff --git a/superset-frontend/src/explore/components/controls/DeckSlicesControl/index.tsx b/superset-frontend/src/explore/components/controls/DeckSlicesControl/index.tsx index 743fd93b6f..1189327890 100644 --- a/superset-frontend/src/explore/components/controls/DeckSlicesControl/index.tsx +++ b/superset-frontend/src/explore/components/controls/DeckSlicesControl/index.tsx @@ -95,6 +95,7 @@ interface SliceSettings { legendCollapsed: boolean; initiallyHidden: boolean; lazyLoading: boolean; + lassoSelectable: boolean; } interface SelectedSliceRowProps { @@ -104,6 +105,7 @@ interface SelectedSliceRowProps { legendCollapsed: boolean; initiallyHidden: boolean; lazyLoading: boolean; + lassoSelectable: boolean; index: number; onRemove: (sliceId: number) => void; onMoveLabel: (dragIndex: number, hoverIndex: number) => void; @@ -167,6 +169,7 @@ const SelectedSliceRow = ({ legendCollapsed, initiallyHidden, lazyLoading, + lassoSelectable, index, onRemove, onMoveLabel, @@ -185,6 +188,8 @@ const SelectedSliceRow = ({ const [draftInitiallyHidden, setDraftInitiallyHidden] = useState(initiallyHidden); const [draftLazyLoading, setDraftLazyLoading] = useState(lazyLoading); + const [draftLassoSelectable, setDraftLassoSelectable] = + useState(lassoSelectable); // Reset draft state when popover opens const handleOpenChange = (open: boolean) => { @@ -193,6 +198,7 @@ const SelectedSliceRow = ({ setDraftLegendCollapsed(legendCollapsed); setDraftInitiallyHidden(initiallyHidden); setDraftLazyLoading(lazyLoading); + setDraftLassoSelectable(lassoSelectable); autozoomBeforeLazyRef.current = autozoom; } setSettingsOpen(open); @@ -220,18 +226,21 @@ const SelectedSliceRow = ({ const legendCollapsedChanged = draftLegendCollapsed !== legendCollapsed; const initiallyHiddenChanged = draftInitiallyHidden !== initiallyHidden; const lazyLoadingChanged = draftLazyLoading !== lazyLoading; + const lassoSelectableChanged = draftLassoSelectable !== lassoSelectable; if ( autozoomChanged || legendCollapsedChanged || initiallyHiddenChanged || - lazyLoadingChanged + lazyLoadingChanged || + lassoSelectableChanged ) { onUpdateSliceSettings(sliceId, { autozoom: draftAutozoom, legendCollapsed: draftLegendCollapsed, initiallyHidden: draftInitiallyHidden, lazyLoading: draftLazyLoading, + lassoSelectable: draftLassoSelectable, }); } setSettingsOpen(false); @@ -354,6 +363,26 @@ const SelectedSliceRow = ({ + + setDraftLassoSelectable(!draftLassoSelectable)} + /> + {t('Lasso Selectable')} + + + + + +