@opengeoweb/core 19.6.0 → 19.6.1-nightly-20260912

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -2,19 +2,19 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { FormControl, MenuItem, Grid, InputLabel, Paper, Box, Typography, CircularProgress, List, ListSubheader, ListItemButton, ListItemText, DialogContentText, TextField, InputAdornment, Button, useTheme, Tooltip, ListItem, ListItemIcon, Checkbox, Popper, Fade, styled, LinearProgress, Autocomplete, Switch, Select } from '@mui/material';
3
3
  import React, { useMemo, useState, useCallback, useEffect, useContext } from 'react';
4
4
  import { safelyInitI18nForTestsAndStories, sharedTranslations, SHARED_NAMESPACE, TooltipSelect, CustomIconButton, CustomDialog, CustomTooltip, ToggleMenu, AlertIcon, useConfirmationDialog, useScrollingInIsolation, sliderHeaderStyle, CustomSlider, SearchField, SearchHighlight, tooltipContainerStyles, renderCounter, AlertBanner, CustomAccordion, PROJECTION, calculateStartSize, useWheelStopPropagation, ToolContainerDraggable, dateUtils, sessionStorageProvider, useDebounce, usePrevious } from '@opengeoweb/shared';
5
- import { webmapUtils, queryWMSLayersTree, invalidateWMSGetCapabilities, LayerType, WMJSDimension, WMDefaultStyleName, WMJSMAP_LONLAT_EPSGCODE, queryWMSServiceInfo, queryWMSLayers, getWMSServiceId, handleDateUtilsISOString, generateLayerId, getWMLayerById, getMapDimURL, WMLayer } from '@opengeoweb/webmap';
5
+ import { webmapUtils, queryWMSLayersTree, invalidateWMSGetCapabilities, LayerType, WMJSDimension, WMDefaultStyleName, queryWMSServiceInfo, queryWMSLayers, getWMSServiceId, handleDateUtilsISOString, generateLayerId, getWMLayerById, getMapDimURL, WMLayer } from '@opengeoweb/webmap';
6
6
  import _, { isEqual, isArray, range, zip, throttle } from 'lodash';
7
7
  import { useDispatch, useSelector, connect, useStore, shallowEqual, Provider } from 'react-redux';
8
8
  import { mapSelectors, layerSelectors, layerActions, layerTypes, filterLayers, mapActions, mapEnums, loadingIndicatorSelectors, layerUtils, serviceSelectors, serviceActions, uiSelectors, uiTypes, useSetupDialog, getUserAddedServices, uiActions, genericActions, drawingToolSelectors, syncGroupsSelectors, syncConstants, getViewObjectForSyncGroup, getViewObjectForMapId, loadingIndicatorActions, genericSelectors, PUBLIC_WARNING_DRAW_TOOL_ID, defaultLayers, getSingularDrawtoolDrawLayerId, syncGroupsSelector, syncGroupsActions, routerUtils, mapUtils } from '@opengeoweb/store';
9
9
  import i18n from 'i18next';
10
10
  import { useTranslation, Trans, I18nextProvider } from 'react-i18next';
11
- import { TIME_SLIDER_NAMESPACE, timesliderTranslations, defaultTimeSpan, AnimationLengthButton, AnimationLength, AutoUpdateButton, BackwardForwardStepButton, NowButton, handleSetNowEvent, PlayButton, defaultTimeStep, SpeedButton, TimeSpanButton, secondsPerPxFromCanvasWidth, getNewCenterOfFixedPointZoom, TimeStepButton, OptionsMenuButton, TimeSliderButtons, TimeSliderCurrentTimeBox, TimeSliderLegend, onsetNewDateDebounced, getFilteredTime, defaultSecondsPerPx, moveSelectedTimePx, TimeSlider } from '@opengeoweb/time-slider';
12
- import { webmapReactTranslations, WEBMAP_REACT_NAMESPACE, webmapTranslations, WEBMAP_NAMESPACE, openLayersGetMapImageStore, LayerInfoButton, useStacCollection, useGetWMLayerInstance, useEDRGetCollectionDetails, getStacCollectionStyles, resolvePreferredStyleName, defaultEdrStyles, LayerInfoDialog, MapControlButton, MapDimensionSelect, dimensionConfig, DimensionSelectDialog, DimensionSelectButton, Clock, LegendDialog, LegendButton, MapContext, emptyGeoJSON, MapFeatureClass, setMapCenter, makeTimeList, getIsInsideAcceptanceTime, OpenLayersLayer, isGeoJSONGeometryEmpty, OpenLayersFeatureLayer, OpenLayersMapDraw, MapMeasure, useSetIntervalWhenVisible, TimeContext, OpenLayersMapView, WMSLayer, genericOpenLayersFeatureStyle, OpenLayersGetFeatureInfo, MapControls, OpenLayersZoomControl, getLayerUpdateInfo, publicLayers } from '@opengeoweb/webmap-react';
11
+ import { TIME_SLIDER_NAMESPACE, timesliderTranslations, defaultTimeSpan, AnimationLengthPanel, exactAnimationLength, AnimationLengthMode, isValidAnimationLength, isWithinAnimationStepLimit, resolveNowAnimationRange, AutoUpdateButton, BackwardForwardStepButton, NowButton, handleSetNowEvent, PlayButton, defaultTimeStep, SpeedButton, TimeSpanButton, secondsPerPxFromCanvasWidth, getNewCenterOfFixedPointZoom, TimeStepButton, OptionsMenuButton, TimeSliderButtons, TimeSliderCurrentTimeBox, TimeSliderLegend, onsetNewDateDebounced, getFilteredTime, defaultSecondsPerPx, moveSelectedTimePx, TimeSlider } from '@opengeoweb/time-slider';
12
+ import { webmapReactTranslations, WEBMAP_REACT_NAMESPACE, webmapTranslations, WEBMAP_NAMESPACE, openLayersGetMapImageStore, LayerInfoButton, useStacCollection, useGetWMLayerInstance, getLayerExtentForProjection, useEDRGetCollectionDetails, getStacCollectionStyles, resolvePreferredStyleName, defaultEdrStyles, LayerInfoDialog, MapControlButton, MapDimensionSelect, dimensionConfig, DimensionSelectDialog, DimensionSelectButton, Clock, LegendDialog, LegendButton, MapContext, emptyGeoJSON, MapFeatureClass, setMapCenter, makeTimeList, getIsInsideAcceptanceTime, OpenLayersLayer, isGeoJSONGeometryEmpty, calculateNewSelection, shouldExitEditModeForMultiSelect, shouldEnterEditMode, calculateBoxSelection, OpenLayersFeatureLayer, OpenLayersMapDraw, DRAWMODE, getOlFeatureKey, MapMeasure, useViewFromLayer, useSetIntervalWhenVisible, TimeContext, OpenLayersMapView, WMSLayer, genericOpenLayersFeatureStyle, OpenLayersGetFeatureInfo, MapControls, OpenLayersZoomControl, getLayerUpdateInfo, publicLayers } from '@opengeoweb/webmap-react';
13
+ export { getAffectedIndices } from '@opengeoweb/webmap-react';
13
14
  import { Cached, Add, MapAdd, CollapseSmall, CollapseMedium, CollapseLarge, CollapseWindow, ExpandWindow, LayersAdd, CloudLoading, ColumnCollapsed, ColumnCollapse, DragHandle as DragHandle$1, None, FastForward, AutoUpdateActive, Both, Delete, Visibility, VisibilityOff, Copy, ZoomToLayer, Overlayers, WorldMapProjection, Layers, Search, Exclamation, MyLocation, Airplane, Region, Pinned, Close, ExitDomain, LocationInfo, Measure, Options, Info, ThemeWrapper, lightTheme, FlagBritain, FlagNetherlands, FlagFinland, FlagNorway } from '@opengeoweb/theme';
14
15
  import { ReactSortable } from 'react-sortablejs';
15
16
  import Sortable from 'sortablejs';
16
17
  import { Box as Box$1, Stack } from '@mui/system';
17
- import { transformExtent, toLonLat, fromLonLat } from 'ol/proj';
18
18
  import { LayerSelectButtonConnect, LayerSelectConnect, DataExplorerButtonConnect } from '@opengeoweb/layer-select';
19
19
  import { unByKey } from 'ol/Observable';
20
20
  import { useQuery, QueryClient, QueryClientProvider } from '@tanstack/react-query';
@@ -23,6 +23,7 @@ import { bbox } from '@turf/turf';
23
23
  import proj4 from 'proj4';
24
24
  import { getIntersection } from 'ol/extent';
25
25
  import GeoJSON from 'ol/format/GeoJSON';
26
+ import { toLonLat, fromLonLat } from 'ol/proj';
26
27
  import { ImageWMS } from 'ol/source';
27
28
  import DOMPurify from 'dompurify';
28
29
  import { snackbarTypes, snackbarActions, SnackbarWrapperConnect } from '@opengeoweb/snackbar';
@@ -4511,13 +4512,12 @@ var LayerManagerMenuButtonConnect = function LayerManagerMenuButtonConnect(_ref)
4511
4512
  if (!layerId || !mapSrs || !wmLayer) {
4512
4513
  return;
4513
4514
  }
4514
- var crs = wmLayer.getCRSByName(mapSrs);
4515
- if (crs != null && crs.bbox) {
4516
- var _crs$bbox$getExtent = crs.bbox.getExtent(),
4517
- left = _crs$bbox$getExtent[0],
4518
- bottom = _crs$bbox$getExtent[1],
4519
- right = _crs$bbox$getExtent[2],
4520
- top = _crs$bbox$getExtent[3];
4515
+ var extent = getLayerExtentForProjection(wmLayer, mapSrs);
4516
+ if (extent) {
4517
+ var left = extent[0],
4518
+ bottom = extent[1],
4519
+ right = extent[2],
4520
+ top = extent[3];
4521
4521
  dispatch(mapActions.setBbox({
4522
4522
  mapId: mapId,
4523
4523
  srs: mapSrs,
@@ -4529,26 +4529,6 @@ var LayerManagerMenuButtonConnect = function LayerManagerMenuButtonConnect(_ref)
4529
4529
  },
4530
4530
  origin: layerTypes.LayerActionOrigin.layerManager
4531
4531
  }));
4532
- return;
4533
- }
4534
- var geo = wmLayer.geographicBoundingBox;
4535
- if (geo) {
4536
- var _transformExtent = transformExtent([parseFloat(geo.west), parseFloat(geo.south), parseFloat(geo.east), parseFloat(geo.north)], WMJSMAP_LONLAT_EPSGCODE, mapSrs),
4537
- _left = _transformExtent[0],
4538
- _bottom = _transformExtent[1],
4539
- _right = _transformExtent[2],
4540
- _top = _transformExtent[3];
4541
- dispatch(mapActions.setBbox({
4542
- mapId: mapId,
4543
- srs: mapSrs,
4544
- bbox: {
4545
- left: _left,
4546
- bottom: _bottom,
4547
- right: _right,
4548
- top: _top
4549
- },
4550
- origin: layerTypes.LayerActionOrigin.layerManager
4551
- }));
4552
4532
  }
4553
4533
  }, [dispatch, layerId, mapId, mapSrs, wmLayer]);
4554
4534
  var duplicateLayer = React.useCallback(function (_ref3) {
@@ -4579,9 +4559,9 @@ var LayerManagerMenuButtonConnect = function LayerManagerMenuButtonConnect(_ref)
4579
4559
  icon: icon,
4580
4560
  isFeatureLayer: isFeatureLayer,
4581
4561
  isFeatureSyncLayer: isFeatureSyncLayer,
4562
+ isTiledStacCollection: isStacGeoTIFFLayer ? isTiledStacCollection : undefined,
4582
4563
  layerId: layerId,
4583
4564
  mapId: mapId,
4584
- isTiledStacCollection: isStacGeoTIFFLayer ? isTiledStacCollection : undefined,
4585
4565
  onChangeStacDataLayout: isStacGeoTIFFLayer ? changeStacDataLayout : undefined,
4586
4566
  onLayerCopyToOtherMaps: copyLayerToOtherMaps,
4587
4567
  onLayerDuplicate: function onLayerDuplicate() {
@@ -6610,56 +6590,75 @@ var MultiMapMultiDimensionSelectConnect = function MultiMapMultiDimensionSelectC
6610
6590
  });
6611
6591
  };
6612
6592
 
6613
- var AnimationLengthButtonConnect = function AnimationLengthButtonConnect(_ref) {
6593
+ var AnimationLengthPanelConnect = function AnimationLengthPanelConnect(_ref) {
6614
6594
  var mapId = _ref.mapId;
6615
6595
  var dispatch = useDispatch();
6616
6596
  var isAnimating = useSelector(function (store) {
6617
6597
  return mapSelectors.isAnimating(store, mapId);
6618
6598
  });
6619
- var isAnimationLengthAuto = useSelector(function (store) {
6620
- return mapSelectors.isAnimationLengthAuto(store, mapId);
6599
+ var animationLength = useSelector(function (store) {
6600
+ return mapSelectors.getAnimationLength(store, mapId);
6621
6601
  });
6622
6602
  var _useSelector = useSelector(function (store) {
6623
6603
  return mapSelectors.getAnimationRange(store, mapId);
6624
6604
  }),
6625
6605
  animationStartTime = _useSelector.animationStartTime,
6626
6606
  animationEndTime = _useSelector.animationEndTime;
6627
- var currentDiffInMinutes = dateUtils.differenceInMinutes(dateUtils.utc(animationEndTime), dateUtils.utc(animationStartTime));
6628
- var handlechangeAnimationLength = function handlechangeAnimationLength(length) {
6629
- var newStartTime = dateUtils.dateToIsoString(dateUtils.add(dateUtils.utc(animationEndTime), {
6630
- minutes: -length
6631
- }));
6632
- dispatch(mapActions.setAnimationStartTime({
6633
- mapId: mapId,
6634
- animationStartTime: newStartTime || dateUtils.dateToIsoString(dateUtils.utc()),
6635
- origin: mapEnums.MapActionOrigin.map
6636
- }));
6637
- dispatch(mapActions.setAnimationEndTime({
6638
- mapId: mapId,
6639
- animationEndTime: animationEndTime || dateUtils.dateToIsoString(dateUtils.utc()),
6640
- origin: mapEnums.MapActionOrigin.map
6641
- }));
6642
- };
6643
- var toggleAnimationLengthAuto = React.useCallback(function () {
6644
- dispatch(mapActions.toggleAnimationLengthAuto({
6645
- mapId: mapId,
6646
- autoAnimationLength: true,
6647
- origin: mapEnums.MapActionOrigin.map
6648
- }));
6649
- }, [dispatch, mapId]);
6650
- var autoTimestepLayerId = useSelector(function (store) {
6607
+ var autoTimeStepLayerId = useSelector(function (store) {
6651
6608
  return mapSelectors.getAutoTimeStepLayerId(store, mapId);
6652
6609
  });
6610
+ var autoTimeStepLayerName = useSelector(function (store) {
6611
+ return autoTimeStepLayerId ? layerSelectors.getLayerTitleFromService(store, autoTimeStepLayerId) : undefined;
6612
+ });
6653
6613
  var timeStepFromLayer = useSelector(function (store) {
6654
- return layerSelectors.getTimeStepForLayerId(store, autoTimestepLayerId);
6614
+ return layerSelectors.getTimeStepForLayerId(store, autoTimeStepLayerId);
6615
+ });
6616
+ var timeStep = useSelector(function (store) {
6617
+ return mapSelectors.getMapTimeStep(store, mapId);
6655
6618
  });
6656
- return jsx(AnimationLengthButton, {
6657
- animationLength: currentDiffInMinutes || Number(AnimationLength.Hours24),
6619
+ var changeAnimationLength = function changeAnimationLength(animationLength) {
6620
+ if (animationLength.mode === AnimationLengthMode.Exact) {
6621
+ var exactStartTime = animationLength.animationStartTime,
6622
+ exactEndTime = animationLength.animationEndTime;
6623
+ var defaultStartDate = dateUtils.sub(dateUtils.utc().setSeconds(0, 0), {
6624
+ days: 1
6625
+ }).toISOString();
6626
+ var defaultEndDate = dateUtils.add(dateUtils.utc().setSeconds(0, 0), {
6627
+ days: 1
6628
+ }).toISOString();
6629
+ var _animationStartTime = exactStartTime || defaultStartDate;
6630
+ var _animationEndTime = exactEndTime || defaultEndDate;
6631
+ dispatch(mapActions.setAnimationLength({
6632
+ mapId: mapId,
6633
+ animationLength: Object.assign({}, exactAnimationLength, {
6634
+ animationStartTime: _animationStartTime,
6635
+ animationEndTime: _animationEndTime
6636
+ }),
6637
+ animationStartTime: _animationStartTime,
6638
+ animationEndTime: _animationEndTime,
6639
+ origin: mapEnums.MapActionOrigin.map
6640
+ }));
6641
+ return;
6642
+ }
6643
+ var followsClock = animationLength.mode === AnimationLengthMode.Now;
6644
+ var isUsableRange = isValidAnimationLength(animationLength) && isWithinAnimationStepLimit(animationLength, timeStep);
6645
+ var resolvedRange = followsClock && isUsableRange ? resolveNowAnimationRange(animationLength) : undefined;
6646
+ dispatch(mapActions.setAnimationLength(Object.assign({
6647
+ mapId: mapId,
6648
+ animationLength: animationLength
6649
+ }, resolvedRange, {
6650
+ origin: mapEnums.MapActionOrigin.map
6651
+ })));
6652
+ };
6653
+ return jsx(AnimationLengthPanel, {
6654
+ animationEndTime: animationEndTime,
6655
+ animationStartTime: animationStartTime,
6656
+ autoTimeStepLayerName: autoTimeStepLayerName,
6658
6657
  disabled: isAnimating,
6659
- isAuto: isAnimationLengthAuto,
6660
- layerHasTimeStep: Boolean(timeStepFromLayer),
6661
- onChangeAnimationLength: handlechangeAnimationLength,
6662
- toggleAnimationLengthAuto: toggleAnimationLengthAuto
6658
+ isAutoDisabled: !timeStepFromLayer,
6659
+ onChange: changeAnimationLength,
6660
+ setting: animationLength != null ? animationLength : exactAnimationLength,
6661
+ timeStep: timeStep
6663
6662
  });
6664
6663
  };
6665
6664
 
@@ -6973,9 +6972,9 @@ var OptionsMenu = function OptionsMenu(_ref) {
6973
6972
  children: [jsx(NowButtonConnect, {
6974
6973
  mapId: mapId,
6975
6974
  sourceId: mapId
6976
- }), jsx(TimeSpanButtonConnect, {
6975
+ }), jsx(AnimationLengthPanelConnect, {
6977
6976
  mapId: mapId
6978
- }), jsx(AnimationLengthButtonConnect, {
6977
+ }), jsx(TimeSpanButtonConnect, {
6979
6978
  mapId: mapId
6980
6979
  }), jsx(_TimeStepButtonConnect, {
6981
6980
  mapId: mapId
@@ -8357,9 +8356,91 @@ var OlMapViewLayerConnect = function OlMapViewLayerConnect(layerProps) {
8357
8356
  }), "layer-" + (layer == null ? void 0 : layer.id));
8358
8357
  };
8359
8358
 
8360
- var getCurrentSelectedIndices = function getCurrentSelectedIndices(_ref) {
8361
- var geojson = _ref.geojson,
8362
- selectedFeatureIds = _ref.selectedFeatureIds;
8359
+ /** Escape drops a multi selection only. A sole selection is kept, matching the
8360
+ * plain click behaviour, and edit mode keeps its own Escape handling. */
8361
+ var shouldDeselectAllOnEscape = function shouldDeselectAllOnEscape(selectedFeatureCount, isInEditMode, hasRegisteredDrawTool) {
8362
+ return hasRegisteredDrawTool && !isInEditMode && selectedFeatureCount > 1;
8363
+ };
8364
+ var useDeselectAllOnEscape = function useDeselectAllOnEscape(_ref) {
8365
+ var selectedFeatureCount = _ref.selectedFeatureCount,
8366
+ isInEditMode = _ref.isInEditMode,
8367
+ hasRegisteredDrawTool = _ref.hasRegisteredDrawTool,
8368
+ onDeselectAll = _ref.onDeselectAll;
8369
+ React.useEffect(function () {
8370
+ if (!shouldDeselectAllOnEscape(selectedFeatureCount, isInEditMode, hasRegisteredDrawTool)) {
8371
+ return undefined;
8372
+ }
8373
+ var onKeyDown = function onKeyDown(event) {
8374
+ if (event.key !== 'Escape' || document.activeElement !== document.body) {
8375
+ return;
8376
+ }
8377
+ onDeselectAll();
8378
+ };
8379
+ window.addEventListener('keydown', onKeyDown);
8380
+ return function () {
8381
+ return window.removeEventListener('keydown', onKeyDown);
8382
+ };
8383
+ }, [selectedFeatureCount, isInEditMode, hasRegisteredDrawTool, onDeselectAll]);
8384
+ };
8385
+ var shouldClearSelectionOnEmptyClick = function shouldClearSelectionOnEmptyClick(activeDrawToolId, hasRegisteredDrawTool) {
8386
+ return !activeDrawToolId && hasRegisteredDrawTool;
8387
+ };
8388
+ var isSketchInProgress = function isSketchInProgress(isInEditMode, drawMode, activeFeature) {
8389
+ if (!isInEditMode) {
8390
+ return false;
8391
+ }
8392
+ if (drawMode === DRAWMODE.SPLIT) {
8393
+ return true;
8394
+ }
8395
+ return Boolean(activeFeature && isGeoJSONGeometryEmpty(activeFeature));
8396
+ };
8397
+ /** Soundings and time series set their own highlight, so they must stay out of this. */
8398
+ var usesFeatureIdSelection = function usesFeatureIdSelection(isSelectable, hasRegisteredDrawTool) {
8399
+ return Boolean(isSelectable) || hasRegisteredDrawTool;
8400
+ };
8401
+ var getSelectionProperties = function getSelectionProperties(usesIdSelection, selectedFeatureIdSet, featureId) {
8402
+ if (!usesIdSelection) {
8403
+ return undefined;
8404
+ }
8405
+ var isSelected = featureId !== undefined && selectedFeatureIdSet.has(featureId);
8406
+ return {
8407
+ isSelected: isSelected,
8408
+ highlightSelectedFeature: isSelected
8409
+ };
8410
+ };
8411
+ var getClickedFeatureKey = getOlFeatureKey;
8412
+ var findFeatureIndexByKey = function findFeatureIndexByKey(geojson, feature) {
8413
+ var key = getClickedFeatureKey(feature);
8414
+ // -1 when the feature has no key, so an unidentifiable click never matches feature 0
8415
+ if (key === undefined || !geojson) {
8416
+ return -1;
8417
+ }
8418
+ return geojson.features.findIndex(function (feat) {
8419
+ return layerUtils.getFeatureSelectionKey(feat) === key;
8420
+ });
8421
+ };
8422
+ var getMovableSelectedFeatureIds = function getMovableSelectedFeatureIds(geojson, selectedFeatureIds) {
8423
+ if (!(geojson != null && geojson.features.length) || !(selectedFeatureIds != null && selectedFeatureIds.length)) {
8424
+ return [];
8425
+ }
8426
+ var selectedFeatureIdSet = new Set(selectedFeatureIds);
8427
+ return geojson.features.reduce(function (featureIds, feature) {
8428
+ var _feature$properties;
8429
+ var featureKey = layerUtils.getFeatureSelectionKey(feature);
8430
+ if (featureKey && selectedFeatureIdSet.has(featureKey) && ((_feature$properties = feature.properties) == null ? void 0 : _feature$properties.isReadonly) !== true) {
8431
+ featureIds.push(featureKey);
8432
+ }
8433
+ return featureIds;
8434
+ }, []);
8435
+ };
8436
+ /** Moving a set of shapes belongs to the drawing tool only: selection-only
8437
+ * reference layers stay selectable but must never be dragged. */
8438
+ var shouldEnableMultiShapeMove = function shouldEnableMultiShapeMove(hasRegisteredDrawTool, isInEditMode, selectedFeatureCount, movableFeatureCount) {
8439
+ return hasRegisteredDrawTool && !isInEditMode && selectedFeatureCount > 1 && movableFeatureCount > 0;
8440
+ };
8441
+ var getCurrentSelectedIndices = function getCurrentSelectedIndices(_ref2) {
8442
+ var geojson = _ref2.geojson,
8443
+ selectedFeatureIds = _ref2.selectedFeatureIds;
8363
8444
  if (!(geojson != null && geojson.features.length) || !(selectedFeatureIds != null && selectedFeatureIds.length)) {
8364
8445
  return [];
8365
8446
  }
@@ -8372,46 +8453,12 @@ var getCurrentSelectedIndices = function getCurrentSelectedIndices(_ref) {
8372
8453
  return indices;
8373
8454
  }, []);
8374
8455
  };
8375
- var calculateNewSelection = function calculateNewSelection(currentSelectedIndices, clickedIndex, isShiftClick) {
8376
- if (isShiftClick) {
8377
- if (currentSelectedIndices.includes(clickedIndex)) {
8378
- return currentSelectedIndices.filter(function (i) {
8379
- return i !== clickedIndex;
8380
- });
8381
- }
8382
- return [].concat(currentSelectedIndices, [clickedIndex]);
8383
- }
8384
- var isSoleSelection = currentSelectedIndices.length === 1 && currentSelectedIndices[0] === clickedIndex;
8385
- return isSoleSelection ? [] : [clickedIndex];
8386
- };
8387
- var getAffectedIndices = function getAffectedIndices(oldSelection, newSelection) {
8388
- var allIndices = new Set([].concat(oldSelection, newSelection));
8389
- return Array.from(allIndices).filter(function (idx) {
8390
- return oldSelection.includes(idx) !== newSelection.includes(idx);
8391
- });
8392
- };
8393
- var shouldEnterEditMode = function shouldEnterEditMode(isReadonly, isShiftClick, newSelectionCount) {
8394
- return !isReadonly && !isShiftClick && newSelectionCount === 1;
8395
- };
8396
- var updateFeatureSelectionProperties = function updateFeatureSelectionProperties(dispatch, layerId, affectedIndices, newSelection) {
8397
- affectedIndices.forEach(function (idx) {
8398
- var isNowSelected = newSelection.includes(idx);
8399
- dispatch(layerActions.updateFeatureProperties({
8400
- layerId: layerId,
8401
- properties: {
8402
- highlightSelectedFeature: isNowSelected,
8403
- isSelected: isNowSelected
8404
- },
8405
- targetFeatureIndex: idx
8406
- }));
8407
- });
8408
- };
8409
- var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref2) {
8410
- var layer = _ref2.layer,
8411
- layerId = _ref2.layerId,
8412
- zIndex = _ref2.zIndex,
8413
- style = _ref2.style,
8414
- hoverSelect = _ref2.hoverSelect;
8456
+ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref3) {
8457
+ var layer = _ref3.layer,
8458
+ layerId = _ref3.layerId,
8459
+ zIndex = _ref3.zIndex,
8460
+ style = _ref3.style,
8461
+ hoverSelect = _ref3.hoverSelect;
8415
8462
  var store = useStore();
8416
8463
  var dispatch = useDispatch();
8417
8464
  var activeDrawToolId = useSelector(drawingToolSelectors.getActiveDrawToolId);
@@ -8433,7 +8480,7 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref2
8433
8480
  return drawingToolSelectors.getGeoJSONIntersectionBoundsLayerId(store, activeDrawToolId);
8434
8481
  });
8435
8482
  var activeFeatureIndex = React.useMemo(function () {
8436
- var _layer$geojson, _currentSelectedFeatu, _ref3;
8483
+ var _layer$geojson, _currentSelectedFeatu, _ref4;
8437
8484
  var currentActiveFeatureIndex = layerUtils.getSelectedFeatureIndexByIds(layer.geojson, layer.selectedFeatureIds);
8438
8485
  if (!shouldAllowMultipleShapes || !(activeDrawMode != null && activeDrawMode.selectionType) || !((_layer$geojson = layer.geojson) != null && _layer$geojson.features.length)) {
8439
8486
  return currentActiveFeatureIndex != null ? currentActiveFeatureIndex : 0;
@@ -8444,9 +8491,9 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref2
8444
8491
  }
8445
8492
  var matchingFeatureIndex;
8446
8493
  for (var index = layer.geojson.features.length - 1; index >= 0; index -= 1) {
8447
- var _feature$properties;
8494
+ var _feature$properties2;
8448
8495
  var feature = layer.geojson.features[index];
8449
- if (((_feature$properties = feature.properties) == null ? void 0 : _feature$properties.selectionType) === activeDrawMode.selectionType) {
8496
+ if (((_feature$properties2 = feature.properties) == null ? void 0 : _feature$properties2.selectionType) === activeDrawMode.selectionType) {
8450
8497
  if (isGeoJSONGeometryEmpty(feature)) {
8451
8498
  return index;
8452
8499
  }
@@ -8455,32 +8502,55 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref2
8455
8502
  }
8456
8503
  }
8457
8504
  }
8458
- return (_ref3 = matchingFeatureIndex != null ? matchingFeatureIndex : currentActiveFeatureIndex) != null ? _ref3 : 0;
8505
+ return (_ref4 = matchingFeatureIndex != null ? matchingFeatureIndex : currentActiveFeatureIndex) != null ? _ref4 : 0;
8459
8506
  }, [activeDrawMode == null ? void 0 : activeDrawMode.selectionType, layer.geojson, layer.selectedFeatureIds, shouldAllowMultipleShapes]);
8507
+ var sketchInProgress = React.useMemo(function () {
8508
+ var _layer$geojson2;
8509
+ return isSketchInProgress(layer.isInEditMode, layer.drawMode, (_layer$geojson2 = layer.geojson) == null ? void 0 : _layer$geojson2.features[activeFeatureIndex]);
8510
+ }, [layer.isInEditMode, layer.drawMode, layer.geojson, activeFeatureIndex]);
8511
+ var usesIdSelection = usesFeatureIdSelection(layer.isSelectable, hasRegisteredDrawTool);
8460
8512
  var displayGeojson = React.useMemo(function () {
8461
- var _layer$hoveredFeature;
8513
+ var _layer$hoveredFeature, _layer$selectedFeatur;
8462
8514
  if (!layer.geojson) {
8463
8515
  return undefined;
8464
8516
  }
8465
8517
  var hoveredFeatureIds = new Set((_layer$hoveredFeature = layer.hoveredFeatureIds) != null ? _layer$hoveredFeature : []);
8518
+ var selectedFeatureIdSet = new Set((_layer$selectedFeatur = layer.selectedFeatureIds) != null ? _layer$selectedFeatur : []);
8466
8519
  return Object.assign({}, layer.geojson, {
8467
8520
  features: layer.geojson.features.map(function (feature) {
8468
- var _feature$properties2;
8521
+ var _feature$properties3;
8469
8522
  var featureId = feature.id !== undefined ? String(feature.id) : undefined;
8470
- var originalId = typeof ((_feature$properties2 = feature.properties) == null ? void 0 : _feature$properties2.originalId) === 'string' ? feature.properties.originalId : layer.originalId;
8523
+ var originalId = typeof ((_feature$properties3 = feature.properties) == null ? void 0 : _feature$properties3.originalId) === 'string' ? feature.properties.originalId : layer.originalId;
8524
+ var selectionProperties = getSelectionProperties(usesIdSelection, selectedFeatureIdSet, featureId);
8471
8525
  return Object.assign({}, feature, {
8472
8526
  properties: Object.assign({}, feature.properties, {
8473
8527
  hover: featureId !== undefined && hoveredFeatureIds.has(featureId) || typeof originalId === 'string' && hoveredFeatureIds.has(originalId)
8474
- })
8528
+ }, selectionProperties)
8475
8529
  });
8476
8530
  })
8477
8531
  });
8478
- }, [layer.geojson, layer.hoveredFeatureIds, layer.originalId]);
8532
+ }, [layer.geojson, layer.hoveredFeatureIds, layer.originalId, layer.selectedFeatureIds, usesIdSelection]);
8533
+ var clearSelection = React.useCallback(function () {
8534
+ if (!shouldClearSelectionOnEmptyClick(activeDrawToolId, hasRegisteredDrawTool)) {
8535
+ return;
8536
+ }
8537
+ dispatch(layerActions.setSelectedFeatures({
8538
+ layerId: layerId,
8539
+ selectedFeatureIds: []
8540
+ }));
8541
+ dispatch(layerActions.toggleFeatureMode({
8542
+ layerId: layerId,
8543
+ isInEditMode: false,
8544
+ drawMode: ''
8545
+ }));
8546
+ }, [activeDrawToolId, hasRegisteredDrawTool, dispatch, layerId]);
8479
8547
  var onFeatureClick = React.useCallback(function (feature, isShiftClick) {
8480
8548
  var _clickedFeature$prope;
8481
- var clickedIndex = layer.geojson.features.findIndex(function (feat) {
8482
- return feature[0] && feat.id === feature[0].getId();
8483
- });
8549
+ if (!feature.length) {
8550
+ clearSelection();
8551
+ return;
8552
+ }
8553
+ var clickedIndex = findFeatureIndexByKey(layer.geojson, feature[0]);
8484
8554
  if (clickedIndex === -1) {
8485
8555
  return;
8486
8556
  }
@@ -8490,10 +8560,9 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref2
8490
8560
  geojson: layer.geojson,
8491
8561
  selectedFeatureIds: layer.selectedFeatureIds
8492
8562
  });
8493
- // When a draw tool is registered for this layer, keep a sole selected
8494
- // feature selected on normal click. Deselecting the active edit target
8495
- // causes edit mode to collapse immediately; clearing selection should
8496
- // instead happen via empty-space click or multi-select interactions.
8563
+ // Drawing layers only: deselecting the active edit target collapses edit mode,
8564
+ // so a plain click on the sole selection keeps it. Clearing happens through
8565
+ // empty space or shift+click instead.
8497
8566
  var shouldPreventDeselect = hasRegisteredDrawTool && !isReadonly && !isShiftClick && currentSelection.length === 1 && currentSelection[0] === clickedIndex;
8498
8567
  var newSelection = shouldPreventDeselect ? [clickedIndex] : calculateNewSelection(currentSelection, clickedIndex, isShiftClick != null ? isShiftClick : false);
8499
8568
  var nextSelectedFeatureIds = newSelection.map(function (index) {
@@ -8505,25 +8574,13 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref2
8505
8574
  layerId: layerId,
8506
8575
  selectedFeatureIds: nextSelectedFeatureIds
8507
8576
  }));
8508
- if (newSelection.length === 0) {
8577
+ if (newSelection.length === 0 || shouldExitEditModeForMultiSelect(newSelection.length)) {
8509
8578
  dispatch(layerActions.toggleFeatureMode({
8510
8579
  layerId: layerId,
8511
8580
  isInEditMode: false,
8512
8581
  drawMode: ''
8513
8582
  }));
8514
8583
  }
8515
- var affectedIndices = getAffectedIndices(currentSelection, newSelection);
8516
- affectedIndices.forEach(function (idx) {
8517
- var isNowSelected = newSelection.includes(idx);
8518
- dispatch(layerActions.updateFeatureProperties({
8519
- layerId: layerId,
8520
- properties: {
8521
- highlightSelectedFeature: isNowSelected,
8522
- isSelected: isNowSelected
8523
- },
8524
- targetFeatureIndex: idx
8525
- }));
8526
- });
8527
8584
  if (shouldEnterEditMode(isReadonly, isShiftClick != null ? isShiftClick : false, newSelection.length)) {
8528
8585
  dispatch(layerActions.toggleFeatureMode({
8529
8586
  layerId: layerId,
@@ -8531,27 +8588,15 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref2
8531
8588
  drawMode: ''
8532
8589
  }));
8533
8590
  }
8534
- }, [hasRegisteredDrawTool, dispatch, layer.geojson, layer.selectedFeatureIds, layerId]);
8535
- var onNoFeatureClick = React.useCallback(function () {
8536
- if (activeDrawToolId) {
8537
- // do not disable edit mode when a drawing tool is active
8538
- return;
8539
- }
8540
- dispatch(layerActions.toggleFeatureMode({
8541
- layerId: layerId,
8542
- isInEditMode: false,
8543
- drawMode: ''
8544
- }));
8545
- }, [activeDrawToolId, dispatch, layerId]);
8591
+ }, [hasRegisteredDrawTool, dispatch, layer.geojson, layer.selectedFeatureIds, layerId, clearSelection]);
8592
+ var onNoFeatureClick = clearSelection;
8546
8593
  var onBoxSelect = React.useCallback(function (features, addToSelection) {
8547
- var _layer$geojson2;
8548
- if (!((_layer$geojson2 = layer.geojson) != null && _layer$geojson2.features.length)) {
8594
+ var _layer$geojson3;
8595
+ if (!((_layer$geojson3 = layer.geojson) != null && _layer$geojson3.features.length)) {
8549
8596
  return;
8550
8597
  }
8551
8598
  var boxSelectedIndices = features.map(function (feature) {
8552
- return layer.geojson.features.findIndex(function (feat) {
8553
- return feat.id === feature.getId();
8554
- });
8599
+ return findFeatureIndexByKey(layer.geojson, feature);
8555
8600
  }).filter(function (idx) {
8556
8601
  return idx !== -1;
8557
8602
  });
@@ -8562,7 +8607,7 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref2
8562
8607
  geojson: layer.geojson,
8563
8608
  selectedFeatureIds: layer.selectedFeatureIds
8564
8609
  });
8565
- var newSelection = addToSelection ? Array.from(new Set([].concat(previousSelection, boxSelectedIndices))) : boxSelectedIndices;
8610
+ var newSelection = calculateBoxSelection(previousSelection, boxSelectedIndices, addToSelection);
8566
8611
  var nextSelectedFeatureIds = newSelection.map(function (index) {
8567
8612
  return layerUtils.getFeatureSelectionKey(layer.geojson.features[index]);
8568
8613
  }).filter(function (featureId) {
@@ -8572,21 +8617,66 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref2
8572
8617
  layerId: layerId,
8573
8618
  selectedFeatureIds: nextSelectedFeatureIds
8574
8619
  }));
8575
- var affectedIndices = getAffectedIndices(previousSelection, newSelection);
8576
- updateFeatureSelectionProperties(dispatch, layerId, affectedIndices, newSelection);
8620
+ if (shouldExitEditModeForMultiSelect(newSelection.length)) {
8621
+ dispatch(layerActions.toggleFeatureMode({
8622
+ layerId: layerId,
8623
+ isInEditMode: false,
8624
+ drawMode: ''
8625
+ }));
8626
+ }
8577
8627
  }, [dispatch, layer.geojson, layer.selectedFeatureIds, layerId]);
8578
8628
  var boxSelectConfig = React.useMemo(function () {
8579
- return layer.isSelectable && !layer.isInEditMode ? {
8629
+ return usesIdSelection && !layer.isInEditMode ? {
8580
8630
  onBoxSelect: onBoxSelect,
8581
8631
  active: true
8582
8632
  } : undefined;
8583
- }, [layer.isSelectable, layer.isInEditMode, onBoxSelect]);
8584
- var onViewOnlyFeatureClick = React.useCallback(function (feature) {
8585
- if (activeDrawToolId) {
8633
+ }, [usesIdSelection, layer.isInEditMode, onBoxSelect]);
8634
+ // Mutually exclusive with boxSelectConfig, so only one DragBox is ever live.
8635
+ var editModeBoxSelectConfig = React.useMemo(function () {
8636
+ return usesIdSelection && layer.isInEditMode ? {
8637
+ onBoxSelect: onBoxSelect,
8638
+ active: true
8639
+ } : undefined;
8640
+ }, [usesIdSelection, layer.isInEditMode, onBoxSelect]);
8641
+ var selectedFeatureIndices = React.useMemo(function () {
8642
+ return getCurrentSelectedIndices({
8643
+ geojson: layer.geojson,
8644
+ selectedFeatureIds: layer.selectedFeatureIds
8645
+ });
8646
+ }, [layer.geojson, layer.selectedFeatureIds]);
8647
+ useDeselectAllOnEscape({
8648
+ selectedFeatureCount: selectedFeatureIndices.length,
8649
+ isInEditMode: layer.isInEditMode,
8650
+ hasRegisteredDrawTool: hasRegisteredDrawTool,
8651
+ onDeselectAll: clearSelection
8652
+ });
8653
+ var movableSelectedFeatureIds = React.useMemo(function () {
8654
+ return getMovableSelectedFeatureIds(layer.geojson, layer.selectedFeatureIds);
8655
+ }, [layer.geojson, layer.selectedFeatureIds]);
8656
+ var onMoveEnd = React.useCallback(function (movedFeatures) {
8657
+ if (!layerId || !movedFeatures.length) {
8658
+ return;
8659
+ }
8660
+ dispatch(layerActions.moveFeatures({
8661
+ layerId: layerId,
8662
+ movedFeatures: movedFeatures,
8663
+ geoJSONIntersectionLayerId: geoJSONIntersectionLayerId,
8664
+ geoJSONIntersectionBoundsLayerId: geoJSONIntersectionBoundsLayerId
8665
+ }));
8666
+ }, [dispatch, layerId, geoJSONIntersectionLayerId, geoJSONIntersectionBoundsLayerId]);
8667
+ var moveFeaturesConfig = React.useMemo(function () {
8668
+ var _layer$selectedFeatur2, _layer$selectedFeatur3;
8669
+ return shouldEnableMultiShapeMove(hasRegisteredDrawTool, layer.isInEditMode, (_layer$selectedFeatur2 = (_layer$selectedFeatur3 = layer.selectedFeatureIds) == null ? void 0 : _layer$selectedFeatur3.length) != null ? _layer$selectedFeatur2 : 0, movableSelectedFeatureIds.length) ? {
8670
+ onMoveEnd: onMoveEnd,
8671
+ active: true
8672
+ } : undefined;
8673
+ }, [hasRegisteredDrawTool, layer.isInEditMode, layer.selectedFeatureIds, movableSelectedFeatureIds, onMoveEnd]);
8674
+ var onViewOnlyFeatureClick = React.useCallback(function (feature, isShiftClick) {
8675
+ if (sketchInProgress) {
8586
8676
  return;
8587
8677
  }
8588
- onFeatureClick(feature);
8589
- }, [activeDrawToolId, onFeatureClick]);
8678
+ onFeatureClick(feature, isShiftClick);
8679
+ }, [sketchInProgress, onFeatureClick]);
8590
8680
  var updateFeature = React.useCallback(function (geojson, reason) {
8591
8681
  if (!layerId) {
8592
8682
  window.console.error('updateFeature without layerId');
@@ -8617,18 +8707,20 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref2
8617
8707
  return jsxs(Fragment, {
8618
8708
  children: [jsx(OpenLayersFeatureLayer, {
8619
8709
  boxSelect: boxSelectConfig,
8620
- clickOnFeature: layer.isSelectable ? {
8710
+ clickOnFeature: usesIdSelection && !layer.isInEditMode ? {
8621
8711
  onClick: onFeatureClick,
8622
8712
  hitTolerance: 5
8623
8713
  } : undefined,
8624
8714
  featureCollection: !layer.isInEditMode ? displayGeojson : undefined,
8625
8715
  hoverSelect: hoverSelect,
8626
8716
  layerId: layerId,
8717
+ moveFeatures: moveFeaturesConfig,
8627
8718
  opacity: layer.opacity,
8628
8719
  style: style,
8629
8720
  visible: layer.enabled,
8630
8721
  zIndex: zIndex
8631
8722
  }), jsx(OpenLayersMapDraw, {
8723
+ boxSelect: editModeBoxSelectConfig,
8632
8724
  drawMode: layer.drawMode,
8633
8725
  exitDrawModeCallback: exitFeatureDrawMode,
8634
8726
  geojson: layer.geojson,
@@ -8636,6 +8728,7 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref2
8636
8728
  onNoFeatureClick: onNoFeatureClick,
8637
8729
  onViewOnlyFeatureClick: onViewOnlyFeatureClick,
8638
8730
  selectedFeatureIndex: activeFeatureIndex,
8731
+ selectedFeatureIndices: selectedFeatureIndices,
8639
8732
  updateGeojson: updateFeature,
8640
8733
  viewOnlyStyle: style
8641
8734
  })]
@@ -8659,6 +8752,14 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref2
8659
8752
  * Copyright 2024 - Finnish Meteorological Institute (FMI)
8660
8753
  * Copyright 2024 - The Norwegian Meteorological Institute (MET Norway)
8661
8754
  * */
8755
+ var getStoredViewObjectForMap = function getStoredViewObjectForMap(mapId, store) {
8756
+ var syncGroupState = syncGroupsSelectors.getSynchronizationGroupState(store.getState());
8757
+ var thisAreaSyncGroupId = syncGroupState.groups.allIds.find(function (id) {
8758
+ var group = syncGroupState.groups.byId[id];
8759
+ return group.type === syncConstants.SYNCGROUPS_TYPE_SETBBOX && group.targets.allIds.includes(mapId);
8760
+ });
8761
+ return thisAreaSyncGroupId ? getViewObjectForSyncGroup(thisAreaSyncGroupId) : getViewObjectForMapId(mapId);
8762
+ };
8662
8763
  var useGetOpenLayersView = function useGetOpenLayersView(mapId, store) {
8663
8764
  var _useState = useState(),
8664
8765
  view = _useState[0],
@@ -8666,17 +8767,9 @@ var useGetOpenLayersView = function useGetOpenLayersView(mapId, store) {
8666
8767
  var _useState2 = useState(),
8667
8768
  name = _useState2[0],
8668
8769
  setName = _useState2[1];
8669
- var syncGroupState = syncGroupsSelectors.getSynchronizationGroupState(store.getState());
8670
- var syncGroupView = useMemo(function () {
8671
- var thisAreaSyncGroupId = syncGroupState.groups.allIds.find(function (id) {
8672
- var group = syncGroupState.groups.byId[id];
8673
- return group.type === syncConstants.SYNCGROUPS_TYPE_SETBBOX && group.targets.allIds.includes(mapId);
8674
- });
8675
- return thisAreaSyncGroupId ? getViewObjectForSyncGroup(thisAreaSyncGroupId) : null;
8676
- }, [mapId, syncGroupState.groups]);
8770
+ var storedView = getStoredViewObjectForMap(mapId, store);
8677
8771
  useEffect(function () {
8678
8772
  var mapBbox = mapSelectors.getBbox(store.getState(), mapId);
8679
- var storedView = syncGroupView || getViewObjectForMapId(mapId);
8680
8773
  if (storedView.view.getCenter() === undefined && mapBbox.left !== undefined) {
8681
8774
  storedView.view.fit([mapBbox.left, mapBbox.bottom, mapBbox.right, mapBbox.top]);
8682
8775
  }
@@ -8689,7 +8782,7 @@ var useGetOpenLayersView = function useGetOpenLayersView(mapId, store) {
8689
8782
  return function () {
8690
8783
  unByKey(eventKey);
8691
8784
  };
8692
- }, [syncGroupView, mapId, store]);
8785
+ }, [storedView, mapId, store]);
8693
8786
  return {
8694
8787
  view: view,
8695
8788
  name: name
@@ -9338,6 +9431,60 @@ var MapOptionsButtonConnect = function MapOptionsButtonConnect(_ref) {
9338
9431
  });
9339
9432
  };
9340
9433
 
9434
+ /* *
9435
+ * Licensed under the Apache License, Version 2.0 (the "License");
9436
+ * you may not use this file except in compliance with the License.
9437
+ * You may obtain a copy of the License at
9438
+ *
9439
+ * http://www.apache.org/licenses/LICENSE-2.0
9440
+ *
9441
+ * Unless required by applicable law or agreed to in writing, software
9442
+ * distributed under the License is distributed on an "AS IS" BASIS,
9443
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9444
+ * See the License for the specific language governing permissions and
9445
+ * limitations under the License.
9446
+ *
9447
+ * Copyright 2026 - Koninklijk Nederlands Meteorologisch Instituut (KNMI)
9448
+ * Copyright 2026 - Finnish Meteorological Institute (FMI)
9449
+ * Copyright 2026 - The Norwegian Meteorological Institute (MET Norway)
9450
+ * */
9451
+ var InitialZoomToLayerConnect = function InitialZoomToLayerConnect(_ref) {
9452
+ var mapId = _ref.mapId,
9453
+ onHomeExtentResolved = _ref.onHomeExtentResolved;
9454
+ var initialZoomToLayerId = useSelector(function (store) {
9455
+ return mapSelectors.getInitialZoomToLayerId(store, mapId);
9456
+ });
9457
+ var layer = useSelector(function (store) {
9458
+ return initialZoomToLayerId ? layerSelectors.getLayerById(store, initialZoomToLayerId) : undefined;
9459
+ });
9460
+ var store = useStore();
9461
+ var view = useViewFromLayer(layer);
9462
+ var _useGetWMLayerInstanc = useGetWMLayerInstance(layer),
9463
+ wmLayer = _useGetWMLayerInstanc.wmLayer;
9464
+ var hasResolvedInitialLayerView = React.useRef(false);
9465
+ React.useEffect(function () {
9466
+ var storedView = getStoredViewObjectForMap(mapId, store);
9467
+ if (storedView.view !== view) {
9468
+ storedView.setView(view);
9469
+ }
9470
+ }, [mapId, store, view]);
9471
+ React.useEffect(function () {
9472
+ if (hasResolvedInitialLayerView.current || !wmLayer) {
9473
+ return;
9474
+ }
9475
+ var extent = getLayerExtentForProjection(wmLayer, view.getProjection().getCode());
9476
+ if (extent) {
9477
+ onHomeExtentResolved([].concat(extent));
9478
+ }
9479
+ hasResolvedInitialLayerView.current = true;
9480
+ store.dispatch(mapActions.setPendingInitialZoomToLayer({
9481
+ mapId: mapId,
9482
+ layerId: undefined
9483
+ }));
9484
+ }, [mapId, onHomeExtentResolved, store, view, wmLayer]);
9485
+ return null;
9486
+ };
9487
+
9341
9488
  /**
9342
9489
  * Connected component used to display the map and selected layers.
9343
9490
  * Includes options to disable the map controls and legend.
@@ -9368,6 +9515,9 @@ var OlMapViewConnect = function OlMapViewConnect(_ref) {
9368
9515
  var _React$useState = React.useState(),
9369
9516
  hoverLinkedFeature = _React$useState[0],
9370
9517
  setHoverLinkedFeature = _React$useState[1];
9518
+ var _React$useState2 = React.useState(undefined),
9519
+ derivedHomeExtent = _React$useState2[0],
9520
+ setDerivedHomeExtent = _React$useState2[1];
9371
9521
  var linkedPanelIds = useSelector(function (store) {
9372
9522
  return genericSelectors.selectLinkedPanelIdsForMap(store, mapId);
9373
9523
  });
@@ -9796,11 +9946,11 @@ var OlMapViewConnect = function OlMapViewConnect(_ref) {
9796
9946
  checkIfDataOutdated();
9797
9947
  }, [checkIfDataOutdated]);
9798
9948
  useMapViewLoadingIndicator(mapId, mapLayerIds);
9799
- var _React$useState2 = React.useState({
9949
+ var _React$useState3 = React.useState({
9800
9950
  debugMode: false
9801
9951
  }),
9802
- mapMode = _React$useState2[0],
9803
- setMapMode = _React$useState2[1];
9952
+ mapMode = _React$useState3[0],
9953
+ setMapMode = _React$useState3[1];
9804
9954
  React.useEffect(function () {
9805
9955
  var handleKeyPress = function handleKeyPress(event) {
9806
9956
  if (event.isTrusted && document.activeElement === document.body) {
@@ -9818,9 +9968,12 @@ var OlMapViewConnect = function OlMapViewConnect(_ref) {
9818
9968
  document.removeEventListener('keyup', handleKeyPress);
9819
9969
  };
9820
9970
  }, [mapMode]);
9971
+ var handleInitialHomeExtentResolved = React.useCallback(function (extent) {
9972
+ setDerivedHomeExtent(extent);
9973
+ }, []);
9821
9974
  var homeExtent = React.useMemo(function () {
9822
- return initialBbox && [initialBbox.left, initialBbox.bottom, initialBbox.right, initialBbox.top];
9823
- }, [initialBbox]);
9975
+ return initialBbox ? [initialBbox.left, initialBbox.bottom, initialBbox.right, initialBbox.top] : derivedHomeExtent;
9976
+ }, [derivedHomeExtent, initialBbox]);
9824
9977
  var dialogType = uiTypes.DialogTypes.Search + "-" + mapId;
9825
9978
  var _useSetupDialog = useSetupDialog(dialogType),
9826
9979
  isSearchDialogOpen = _useSetupDialog.isDialogOpen;
@@ -9864,9 +10017,12 @@ var OlMapViewConnect = function OlMapViewConnect(_ref) {
9864
10017
  features: linkedFeatureCollectionsWithHover.features
9865
10018
  };
9866
10019
  }, [linkedFeatureCollectionsWithHover]);
9867
- return jsx(TimeContext.Provider, {
10020
+ return jsxs(TimeContext.Provider, {
9868
10021
  value: prefetchTimespan,
9869
- children: jsxs(OpenLayersMapView, {
10022
+ children: [jsx(InitialZoomToLayerConnect, {
10023
+ mapId: mapId,
10024
+ onHomeExtentResolved: handleInitialHomeExtentResolved
10025
+ }), jsxs(OpenLayersMapView, {
9870
10026
  holdShiftToScroll: holdShiftToScroll,
9871
10027
  isFocused: isActiveWindowId,
9872
10028
  isMouseWheelZoomEnabled: !isTimeScrollingEnabled,
@@ -9958,7 +10114,7 @@ var OlMapViewConnect = function OlMapViewConnect(_ref) {
9958
10114
  }), !!displayTimeInMap && jsx(ClockConnect, {
9959
10115
  mapId: mapId
9960
10116
  }), children]
9961
- })
10117
+ })]
9962
10118
  });
9963
10119
  };
9964
10120
 
@@ -9974,7 +10130,7 @@ var OptionsMenuButtonConnect = function OptionsMenuButtonConnect(_ref) {
9974
10130
  var mapId = _ref.mapId,
9975
10131
  enableKeyboardShortcut = _ref.enableKeyboardShortcut;
9976
10132
  return jsx(OptionsMenuButton, {
9977
- animationLengthBtn: jsx(AnimationLengthButtonConnect, {
10133
+ animationLengthBtn: jsx(AnimationLengthPanelConnect, {
9978
10134
  mapId: mapId
9979
10135
  }),
9980
10136
  enableKeyboardShortcut: enableKeyboardShortcut,
@@ -12276,4 +12432,4 @@ var storyUtils = /*#__PURE__*/Object.freeze({
12276
12432
  useDefaultMapSettings: useDefaultMapSettings
12277
12433
  });
12278
12434
 
12279
- export { CORE_NAMESPACE, _ConfigurableMapConnect as ConfigurableMapConnect, CoreI18nProvider, CoreStoreProvider, CoreThemeProvider, CoreThemeStoreProvider, DemoWrapper, DemoWrapperConnect, HarmonieTempAndPrecipPreset, LanguageSelect, LayerInfoButtonConnect, LayerInfoDialogConnect, _LayerManager as LayerManager, BaseLayerRow as LayerManagerBaseLayerRow, LayerManagerConnect, DescriptionRow as LayerManagerDescriptionRow, HeaderOptions as LayerManagerHeaderOptions, LayerContainerRow as LayerManagerLayerContainerRow, LayerManagerMapButtonConnect, LegendConnect, LegendMapButtonConnect, LoadingIndicatorProgressBar, LocationSearch, LocationSearchConnect, MultiDimensionSelectMapButtonsConnect, MultiMapMultiDimensionSelectConnect as MultiMapDimensionSelectConnect, MultiMapViewConnect, MyMapLocation, OlMapViewConnect, RouterWrapperConnect, SearchControlButtonConnect, SelectedFeaturesDialogConnect, SyncGroupViewerConnect, TIME_SLIDER_Z_INDEX, TimeSliderConnect, componentsLookUp, coreTranslations, defaultBbox, defaultConfigurations, filterMapPresets, filterServices, filterTimeSeriesServices, getAffectedIndices, getCenterOfLinkedFeature, getCurrentSelectedIndices, getIsOutdated, getLanguageFromLocalStorage, getRenderedDimensions, languageLocalStorageKey, makeLayerInfoPayload, makePrefetchTimeSpan, saveLanguageToLocalStorage, storyUtils, testLayers, useFetchServices, useFitAndHighlightWarningFeature, useGetOpenLayersView, useLocationDetail, useLocationList, usePrefetchTimeSpan, useUpdateTimeSpan, useUpdateTimestep };
12435
+ export { CORE_NAMESPACE, _ConfigurableMapConnect as ConfigurableMapConnect, CoreI18nProvider, CoreStoreProvider, CoreThemeProvider, CoreThemeStoreProvider, DemoWrapper, DemoWrapperConnect, HarmonieTempAndPrecipPreset, LanguageSelect, LayerInfoButtonConnect, LayerInfoDialogConnect, _LayerManager as LayerManager, BaseLayerRow as LayerManagerBaseLayerRow, LayerManagerConnect, DescriptionRow as LayerManagerDescriptionRow, HeaderOptions as LayerManagerHeaderOptions, LayerContainerRow as LayerManagerLayerContainerRow, LayerManagerMapButtonConnect, LegendConnect, LegendMapButtonConnect, LoadingIndicatorProgressBar, LocationSearch, LocationSearchConnect, MultiDimensionSelectMapButtonsConnect, MultiMapMultiDimensionSelectConnect as MultiMapDimensionSelectConnect, MultiMapViewConnect, MyMapLocation, OlMapViewConnect, RouterWrapperConnect, SearchControlButtonConnect, SelectedFeaturesDialogConnect, SyncGroupViewerConnect, TIME_SLIDER_Z_INDEX, TimeSliderConnect, componentsLookUp, coreTranslations, defaultBbox, defaultConfigurations, filterMapPresets, filterServices, filterTimeSeriesServices, getCenterOfLinkedFeature, getCurrentSelectedIndices, getIsOutdated, getLanguageFromLocalStorage, getRenderedDimensions, getStoredViewObjectForMap, languageLocalStorageKey, makeLayerInfoPayload, makePrefetchTimeSpan, saveLanguageToLocalStorage, storyUtils, testLayers, useFetchServices, useFitAndHighlightWarningFeature, useGetOpenLayersView, useLocationDetail, useLocationList, usePrefetchTimeSpan, useUpdateTimeSpan, useUpdateTimestep };
@@ -1,15 +1,39 @@
1
+ import type { Feature } from 'ol';
1
2
  import type { StyleLike } from 'ol/style/Style';
2
3
  import React from 'react';
3
4
  import type { layerTypes } from '@opengeoweb/store';
4
5
  import type { HoverSelect } from '@opengeoweb/webmap-react';
6
+ import { getAffectedIndices } from '@opengeoweb/webmap-react';
7
+ export { getAffectedIndices };
8
+ /** Escape drops a multi selection only. A sole selection is kept, matching the
9
+ * plain click behaviour, and edit mode keeps its own Escape handling. */
10
+ export declare const shouldDeselectAllOnEscape: (selectedFeatureCount: number, isInEditMode: boolean | undefined, hasRegisteredDrawTool: boolean) => boolean;
11
+ interface DeselectAllOnEscapeOptions {
12
+ selectedFeatureCount: number;
13
+ isInEditMode: boolean | undefined;
14
+ hasRegisteredDrawTool: boolean;
15
+ onDeselectAll: () => void;
16
+ }
17
+ export declare const useDeselectAllOnEscape: ({ selectedFeatureCount, isInEditMode, hasRegisteredDrawTool, onDeselectAll, }: DeselectAllOnEscapeOptions) => void;
18
+ export declare const shouldClearSelectionOnEmptyClick: (activeDrawToolId: string | undefined, hasRegisteredDrawTool: boolean) => boolean;
19
+ export declare const isSketchInProgress: (isInEditMode: boolean | undefined, drawMode: string | undefined, activeFeature: GeoJSON.Feature | undefined) => boolean;
20
+ /** Soundings and time series set their own highlight, so they must stay out of this. */
21
+ export declare const usesFeatureIdSelection: (isSelectable: boolean | undefined, hasRegisteredDrawTool: boolean) => boolean;
22
+ export declare const getSelectionProperties: (usesIdSelection: boolean, selectedFeatureIdSet: Set<string>, featureId: string | undefined) => {
23
+ isSelected: boolean;
24
+ highlightSelectedFeature: boolean;
25
+ } | undefined;
26
+ export declare const getClickedFeatureKey: (feature?: Feature) => string | undefined;
27
+ export declare const findFeatureIndexByKey: (geojson: GeoJSON.FeatureCollection | undefined, feature?: Feature) => number;
28
+ export declare const getMovableSelectedFeatureIds: (geojson: GeoJSON.FeatureCollection | undefined, selectedFeatureIds: string[] | undefined) => string[];
29
+ /** Moving a set of shapes belongs to the drawing tool only: selection-only
30
+ * reference layers stay selectable but must never be dragged. */
31
+ export declare const shouldEnableMultiShapeMove: (hasRegisteredDrawTool: boolean, isInEditMode: boolean | undefined, selectedFeatureCount: number, movableFeatureCount: number) => boolean;
5
32
  interface SelectionState {
6
33
  geojson?: GeoJSON.FeatureCollection;
7
34
  selectedFeatureIds?: string[];
8
35
  }
9
36
  export declare const getCurrentSelectedIndices: ({ geojson, selectedFeatureIds, }: SelectionState) => number[];
10
- export declare const calculateNewSelection: (currentSelectedIndices: number[], clickedIndex: number, isShiftClick: boolean) => number[];
11
- export declare const getAffectedIndices: (oldSelection: number[], newSelection: number[]) => number[];
12
- export declare const shouldEnterEditMode: (isReadonly: boolean, isShiftClick: boolean, newSelectionCount: number) => boolean;
13
37
  interface OpenLayersFeatureLayerConnectProps {
14
38
  layer: layerTypes.ReduxLayer;
15
39
  layerId?: string;
@@ -18,4 +42,3 @@ interface OpenLayersFeatureLayerConnectProps {
18
42
  hoverSelect?: HoverSelect;
19
43
  }
20
44
  export declare const OpenLayersFeatureLayerConnect: React.FC<OpenLayersFeatureLayerConnectProps>;
21
- export {};
@@ -0,0 +1,8 @@
1
+ import type { Extent } from 'ol/extent';
2
+ import React from 'react';
3
+ interface InitialZoomToLayerConnectProps {
4
+ mapId: string;
5
+ onHomeExtentResolved: (extent: Extent) => void;
6
+ }
7
+ declare const InitialZoomToLayerConnect: React.FC<InitialZoomToLayerConnectProps>;
8
+ export default InitialZoomToLayerConnect;
@@ -1,9 +1,11 @@
1
1
  import type { Store } from '@reduxjs/toolkit';
2
2
  import type { View } from 'ol';
3
+ import { getViewObjectForMapId } from '@opengeoweb/store';
3
4
  import type { CoreAppStore } from '@opengeoweb/store';
4
5
  interface UseGetOpenLayersViewValue {
5
6
  view?: View;
6
7
  name?: string;
7
8
  }
9
+ export declare const getStoredViewObjectForMap: (mapId: string, store: Store<CoreAppStore>) => ReturnType<typeof getViewObjectForMapId>;
8
10
  export declare const useGetOpenLayersView: (mapId: string, store: Store<CoreAppStore>) => UseGetOpenLayersViewValue;
9
11
  export {};
@@ -6,7 +6,7 @@ export declare const mapPresetRadar: {
6
6
  enabled: boolean;
7
7
  style: string;
8
8
  id: string;
9
- layerType: import("@opengeoweb/webmap").LayerType;
9
+ layerType: import("libs/webmap/dist").LayerType;
10
10
  }[];
11
11
  proj: {
12
12
  bbox: {
@@ -23,7 +23,7 @@ export declare const mapPresetObsTA: {
23
23
  service: string;
24
24
  name: string;
25
25
  id: string;
26
- layerType: import("@opengeoweb/webmap").LayerType;
26
+ layerType: import("libs/webmap/dist").LayerType;
27
27
  }[];
28
28
  proj: {
29
29
  bbox: {
@@ -40,7 +40,7 @@ export declare const mapPresetObsWind: {
40
40
  service: string;
41
41
  name: string;
42
42
  id: string;
43
- layerType: import("@opengeoweb/webmap").LayerType;
43
+ layerType: import("libs/webmap/dist").LayerType;
44
44
  }[];
45
45
  proj: {
46
46
  bbox: {
@@ -57,7 +57,7 @@ export declare const mapPresetObsPP: {
57
57
  service: string;
58
58
  name: string;
59
59
  id: string;
60
- layerType: import("@opengeoweb/webmap").LayerType;
60
+ layerType: import("libs/webmap/dist").LayerType;
61
61
  }[];
62
62
  proj: {
63
63
  bbox: {
@@ -74,7 +74,7 @@ export declare const mapPresetObsRH: {
74
74
  service: string;
75
75
  name: string;
76
76
  id: string;
77
- layerType: import("@opengeoweb/webmap").LayerType;
77
+ layerType: import("libs/webmap/dist").LayerType;
78
78
  }[];
79
79
  proj: {
80
80
  bbox: {
@@ -91,7 +91,7 @@ export declare const mapPresetObsQG: {
91
91
  service: string;
92
92
  name: string;
93
93
  id: string;
94
- layerType: import("@opengeoweb/webmap").LayerType;
94
+ layerType: import("libs/webmap/dist").LayerType;
95
95
  }[];
96
96
  proj: {
97
97
  bbox: {
@@ -109,7 +109,7 @@ export declare const mapPresetEumetsat: {
109
109
  name: string;
110
110
  enabled: boolean;
111
111
  id: string;
112
- layerType: import("@opengeoweb/webmap").LayerType;
112
+ layerType: import("libs/webmap/dist").LayerType;
113
113
  }[];
114
114
  proj: {
115
115
  bbox: {
@@ -126,7 +126,7 @@ export declare const mapPresetHarmoniePrecipitationFlux: {
126
126
  service: string;
127
127
  name: string;
128
128
  id: string;
129
- layerType: import("@opengeoweb/webmap").LayerType;
129
+ layerType: import("libs/webmap/dist").LayerType;
130
130
  enabled: boolean;
131
131
  }[];
132
132
  proj: {
@@ -144,7 +144,7 @@ export declare const mapPresetHarmonieTemperature2m: {
144
144
  service: string;
145
145
  name: string;
146
146
  id: string;
147
- layerType: import("@opengeoweb/webmap").LayerType;
147
+ layerType: import("libs/webmap/dist").LayerType;
148
148
  enabled: boolean;
149
149
  }[];
150
150
  proj: {
@@ -162,7 +162,7 @@ export declare const mapPresetHarmoniePressureMSL: {
162
162
  service: string;
163
163
  name: string;
164
164
  id: string;
165
- layerType: import("@opengeoweb/webmap").LayerType;
165
+ layerType: import("libs/webmap/dist").LayerType;
166
166
  enabled: boolean;
167
167
  }[];
168
168
  proj: {
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ export interface AnimationLengthPanelConnectProps {
3
+ mapId: string;
4
+ }
5
+ export declare const AnimationLengthPanelConnect: React.FC<AnimationLengthPanelConnectProps>;
package/package.json CHANGED
@@ -1,64 +1,64 @@
1
1
  {
2
- "name": "@opengeoweb/core",
3
- "version": "19.6.0",
4
- "description": "GeoWeb Core library for the opengeoweb project",
5
- "license": "Apache-2.0",
6
- "repository": {
7
- "type": "git",
8
- "url": "git@gitlab.com:opengeoweb/opengeoweb.git"
9
- },
10
- "main": "./dist/index.esm.js",
11
- "module": "./dist/index.esm.js",
12
- "types": "./dist/index.d.ts",
13
- "exports": {
14
- "./package.json": "./package.json",
15
- ".": {
16
- "@opengeoweb/source": "./src/index.ts",
17
- "types": "./dist/index.d.ts",
18
- "import": "./dist/index.esm.js",
19
- "default": "./dist/index.esm.js"
20
- }
21
- },
22
- "dependencies": {
23
- "@opengeoweb/shared": "*",
24
- "react-redux": "^9.2.0",
25
- "@opengeoweb/store": "*",
26
- "@opengeoweb/time-slider": "*",
27
- "@reduxjs/toolkit": "^2.6.1",
28
- "@opengeoweb/webmap-react": "*",
29
- "@opengeoweb/webmap": "*",
30
- "@opengeoweb/theme": "*",
31
- "@opengeoweb/layer-select": "*",
32
- "lodash": "^4.18.1",
33
- "ol": "^10.4.0",
34
- "react-sortablejs": "^6.1.4",
35
- "sortablejs": "^1.15.1",
36
- "@mui/system": "^9.0.1",
37
- "@opengeoweb/snackbar": "*",
38
- "react-draggable": "^4.4.6",
39
- "i18next": "^25.0.1",
40
- "react-i18next": "^15.1.1",
41
- "dompurify": "^3.4.13",
42
- "@mui/material": "^9.0.1",
43
- "@tanstack/react-query": "^5.85.5",
44
- "@opengeoweb/api": "*",
45
- "@types/geojson": "^7946.0.14",
46
- "@turf/turf": "^7.2.0",
47
- "proj4": "^2.15.0",
48
- "react-router": "^7.18.2"
49
- },
50
- "peerDependencies": {
51
- "react": "19",
52
- "@emotion/react": "*",
53
- "@emotion/styled": "*"
54
- },
55
- "devDependencies": {
56
- "eslint-plugin-storybook": "10.3.3"
57
- },
58
- "files": [
59
- "dist",
60
- "!dist/package.json",
61
- "README.md",
62
- "package.json"
63
- ]
64
- }
2
+ "name": "@opengeoweb/core",
3
+ "version": "19.6.1-nightly-20260912",
4
+ "description": "GeoWeb Core library for the opengeoweb project",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git@gitlab.com:opengeoweb/opengeoweb.git"
9
+ },
10
+ "main": "./dist/index.esm.js",
11
+ "module": "./dist/index.esm.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ "./package.json": "./package.json",
15
+ ".": {
16
+ "@opengeoweb/source": "./src/index.ts",
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.esm.js",
19
+ "default": "./dist/index.esm.js"
20
+ }
21
+ },
22
+ "dependencies": {
23
+ "@opengeoweb/shared": "19.6.1-nightly-20260912",
24
+ "react-redux": "^9.2.0",
25
+ "@opengeoweb/store": "19.6.1-nightly-20260912",
26
+ "@opengeoweb/time-slider": "19.6.1-nightly-20260912",
27
+ "@reduxjs/toolkit": "^2.6.1",
28
+ "@opengeoweb/webmap-react": "19.6.1-nightly-20260912",
29
+ "@opengeoweb/webmap": "19.6.1-nightly-20260912",
30
+ "@opengeoweb/theme": "19.6.1-nightly-20260912",
31
+ "@opengeoweb/layer-select": "19.6.1-nightly-20260912",
32
+ "lodash": "^4.18.1",
33
+ "ol": "^10.4.0",
34
+ "react-sortablejs": "^6.1.4",
35
+ "sortablejs": "^1.15.1",
36
+ "@mui/system": "^9.0.1",
37
+ "@opengeoweb/snackbar": "19.6.1-nightly-20260912",
38
+ "react-draggable": "^4.4.6",
39
+ "i18next": "^25.0.1",
40
+ "react-i18next": "^15.1.1",
41
+ "dompurify": "^3.4.13",
42
+ "@mui/material": "^9.0.1",
43
+ "@tanstack/react-query": "^5.85.5",
44
+ "@opengeoweb/api": "19.6.1-nightly-20260912",
45
+ "@types/geojson": "^7946.0.14",
46
+ "@turf/turf": "^7.2.0",
47
+ "proj4": "^2.15.0",
48
+ "react-router": "^7.18.2"
49
+ },
50
+ "peerDependencies": {
51
+ "react": "19",
52
+ "@emotion/react": "*",
53
+ "@emotion/styled": "*"
54
+ },
55
+ "devDependencies": {
56
+ "eslint-plugin-storybook": "10.3.3"
57
+ },
58
+ "files": [
59
+ "dist",
60
+ "!dist/package.json",
61
+ "README.md",
62
+ "package.json"
63
+ ]
64
+ }