@defra/interactive-map 0.0.40-alpha → 0.0.41-alpha
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/css/index.css +1 -1
- package/dist/esm/im-core.js +1 -1
- package/dist/esm/im-shell.js +1 -1
- package/dist/umd/im-core.js +1 -1
- package/dist/umd/index.js +1 -1
- package/docs/api/control-definition.md +9 -1
- package/docs/api/slots.md +26 -5
- package/docs/assets/images/slot-map.svg +61 -262
- package/docs/examples/draw-tools.mdx +3 -3
- package/docs/plugins/draw.md +79 -16
- package/docs/plugins/search.md +1 -1
- package/govuk-prototype-kit.config.json +2 -0
- package/jest.setup.js +5 -0
- package/package.json +9 -1
- package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
- package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ol/dist/esm/im-draw-ol-plugin.js +1 -1
- package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -1
- package/plugins/beta/map-styles/dist/umd/index.js +1 -1
- package/plugins/datasets/dist/css/index.css +1 -1
- package/plugins/datasets/dist/esm/esriLayerAdapter.js +1 -1
- package/plugins/datasets/dist/esm/im-datasets-ml-adapter.js +1 -1
- package/plugins/datasets/dist/esm/im-datasets-plugin.js +1 -1
- package/plugins/datasets/dist/umd/im-datasets-esri-adapter.js +1 -1
- package/plugins/datasets/dist/umd/im-datasets-ml-adapter.js +1 -1
- package/plugins/datasets/dist/umd/im-datasets-plugin.js +1 -1
- package/plugins/datasets/dist/umd/index.js +1 -1
- package/plugins/datasets/src/adapters/esri/esriLayerAdapter.test.js +175 -0
- package/plugins/datasets/src/adapters/esri/registry/esriDataset.test.js +55 -0
- package/plugins/datasets/src/adapters/loadLayerAdapter.test.js +61 -0
- package/plugins/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js +14 -0
- package/plugins/datasets/src/api/setOpacity.test.js +9 -0
- package/plugins/datasets/src/components/LayersMenu/LayersMenu.jsx +10 -25
- package/plugins/datasets/src/components/LayersMenu/LayersMenu.test.jsx +0 -42
- package/plugins/datasets/src/datasets.scss +0 -1
- package/plugins/datasets/src/fetch/createDynamicSource.js +135 -129
- package/plugins/datasets/src/fetch/createDynamicSource.test.js +318 -0
- package/plugins/datasets/src/fetch/fetchGeoJSON.test.js +83 -0
- package/plugins/datasets/src/index.test.js +36 -0
- package/plugins/datasets/src/initialise/DatasetsInit.jsx +17 -7
- package/plugins/datasets/src/initialise/DatasetsInit.test.jsx +262 -0
- package/plugins/datasets/src/initialise/initialiseDatasets.js +16 -4
- package/plugins/datasets/src/initialise/initialiseDatasets.test.js +42 -0
- package/plugins/datasets/src/manifest.js +0 -38
- package/plugins/datasets/src/manifest.test.js +49 -0
- package/plugins/datasets/src/reducers/datasetsToMenu.test.js +54 -1
- package/plugins/datasets/src/reducers/pluginState.js +3 -16
- package/plugins/datasets/src/reducers/pluginState.test.js +23 -0
- package/plugins/datasets/src/registry/dataset.js +13 -1
- package/plugins/datasets/src/registry/dataset.test.js +61 -0
- package/plugins/datasets/src/registry/datasetRegistry.js +12 -6
- package/plugins/datasets/src/registry/datasetRegistry.test.js +16 -4
- package/plugins/datasets/src/registry/isVisibleWhen.js +6 -3
- package/plugins/datasets/src/registry/isVisibleWhen.test.js +11 -1
- package/plugins/datasets/src/utils/bbox.test.js +125 -0
- package/plugins/draw/dist/esm/im-draw-ml-adapter.js +1 -1
- package/plugins/draw/dist/esm/im-draw-ol-adapter.js +1 -1
- package/plugins/draw/dist/esm/im-draw-plugin.js +1 -1
- package/plugins/draw/dist/esm/index.js +1 -1
- package/plugins/draw/dist/umd/im-draw-ml-adapter.js +2 -1
- package/plugins/draw/dist/umd/im-draw-ml-adapter.js.LICENSE.txt +1 -0
- package/plugins/draw/dist/umd/im-draw-ol-adapter.js +1 -1
- package/plugins/draw/dist/umd/im-draw-plugin.js +1 -1
- package/plugins/draw/dist/umd/index.js +1 -1
- package/plugins/draw/src/DrawInit.jsx +10 -2
- package/plugins/draw/src/DrawInit.test.jsx +51 -10
- package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.js +91 -11
- package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.test.js +246 -4
- package/plugins/draw/src/adapters/maplibre/mapboxDraw.js +109 -14
- package/plugins/draw/src/adapters/maplibre/mapboxDraw.test.js +174 -11
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/clickHandlers.test.js +12 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.js +9 -1
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.test.js +24 -3
- package/plugins/draw/src/adapters/maplibre/modes/drawPointMode.js +194 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawPointMode.test.js +457 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/__helpers__/harness.js +102 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/keyboardHandlers.js +82 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/keyboardHandlers.test.js +83 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointOperations.js +55 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointOperations.test.js +62 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointerHandlers.js +138 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointerHandlers.test.js +197 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/touchHandlers.js +92 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/touchHandlers.test.js +101 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/undoHandlers.js +46 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/undoHandlers.test.js +42 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode.js +151 -0
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode.test.js +156 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.js +4 -27
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.test.js +24 -39
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/pointerHandlers.js +4 -5
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.js +20 -23
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.test.js +25 -5
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.js +6 -36
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.test.js +7 -49
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.js +3 -53
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.test.js +8 -33
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.js +29 -72
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.test.js +10 -3
- package/plugins/draw/src/adapters/maplibre/pointSymbolImages.js +158 -0
- package/plugins/draw/src/adapters/maplibre/pointSymbolImages.test.js +314 -0
- package/plugins/draw/src/adapters/maplibre/snap/prototypePatches.js +6 -1
- package/plugins/draw/src/adapters/maplibre/snap/prototypePatches.test.js +21 -0
- package/plugins/draw/src/adapters/maplibre/snap/snapInstance.js +6 -2
- package/plugins/draw/src/adapters/maplibre/snap/snapInstance.test.js +12 -0
- package/plugins/draw/src/adapters/maplibre/styles.js +38 -11
- package/plugins/draw/src/adapters/maplibre/styles.test.js +39 -0
- package/plugins/draw/src/adapters/maplibre/utils/editModeEvents.js +79 -0
- package/plugins/draw/src/adapters/maplibre/utils/editModeEvents.test.js +135 -0
- package/plugins/draw/src/adapters/maplibre/utils/geometryValidation.js +42 -0
- package/plugins/draw/src/adapters/maplibre/utils/geometryValidation.test.js +85 -0
- package/plugins/draw/src/adapters/maplibre/utils/keyboardShortcuts.js +34 -0
- package/plugins/draw/src/adapters/maplibre/utils/keyboardShortcuts.test.js +78 -0
- package/plugins/draw/src/adapters/maplibre/utils/snapHelpers.js +16 -3
- package/plugins/draw/src/adapters/maplibre/utils/snapHelpers.test.js +21 -3
- package/plugins/draw/src/adapters/maplibre/utils/snapMovement.js +59 -0
- package/plugins/draw/src/adapters/maplibre/utils/snapMovement.test.js +73 -0
- package/plugins/draw/src/adapters/maplibre/utils/touchDragMath.js +33 -0
- package/plugins/draw/src/adapters/maplibre/utils/touchDragMath.test.js +70 -0
- package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.js +27 -2
- package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.test.js +93 -0
- package/plugins/draw/src/adapters/openlayers/__helpers__/harness.js +9 -0
- package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.js +19 -1
- package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.test.js +34 -1
- package/plugins/draw/src/adapters/openlayers/core/styles.js +73 -1
- package/plugins/draw/src/adapters/openlayers/core/styles.test.js +122 -3
- package/plugins/draw/src/adapters/openlayers/draw/DrawMode.test.js +12 -0
- package/plugins/draw/src/adapters/openlayers/draw/drawInput.js +8 -2
- package/plugins/draw/src/adapters/openlayers/edit/EditMode.test.js +31 -0
- package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.js +9 -5
- package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.test.js +33 -0
- package/plugins/draw/src/adapters/openlayers/edit/modifyInteraction.js +5 -3
- package/plugins/draw/src/adapters/openlayers/edit/modifyInteraction.test.js +11 -0
- package/plugins/draw/src/adapters/openlayers/edit/nudge.js +10 -3
- package/plugins/draw/src/adapters/openlayers/edit/nudge.test.js +24 -1
- package/plugins/draw/src/adapters/openlayers/edit/touchHandler.js +18 -13
- package/plugins/draw/src/adapters/openlayers/edit/touchHandler.test.js +46 -1
- package/plugins/draw/src/adapters/openlayers/olDraw.js +11 -4
- package/plugins/draw/src/adapters/openlayers/olDraw.test.js +48 -6
- package/plugins/draw/src/adapters/openlayers/point/drawPointMode.js +156 -0
- package/plugins/draw/src/adapters/openlayers/point/drawPointMode.test.js +246 -0
- package/plugins/draw/src/adapters/openlayers/point/editPointMode.js +267 -0
- package/plugins/draw/src/adapters/openlayers/point/editPointMode.test.js +327 -0
- package/plugins/draw/src/adapters/openlayers/point/pointDragInteraction.js +71 -0
- package/plugins/draw/src/adapters/openlayers/point/pointOps.js +34 -0
- package/plugins/draw/src/adapters/openlayers/point/pointOps.test.js +32 -0
- package/plugins/draw/src/adapters/openlayers/point/pointSelectionState.js +82 -0
- package/plugins/draw/src/adapters/openlayers/point/pointSelectionState.test.js +107 -0
- package/plugins/draw/src/adapters/openlayers/point/pointSymbolImages.js +83 -0
- package/plugins/draw/src/adapters/openlayers/point/pointSymbolImages.test.js +214 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapIndicator.js +3 -1
- package/plugins/draw/src/adapters/openlayers/snap/snapInteraction.js +6 -9
- package/plugins/draw/src/adapters/openlayers/snap/snapInteraction.test.js +15 -4
- package/plugins/draw/src/adapters/openlayers/utils/olCoords.js +1 -1
- package/plugins/draw/src/api/addFeature.js +16 -1
- package/plugins/draw/src/api/addFeature.test.js +62 -5
- package/plugins/draw/src/api/editFeature.js +7 -4
- package/plugins/draw/src/api/editFeature.test.js +16 -0
- package/plugins/draw/src/api/newPoint.js +42 -0
- package/plugins/draw/src/api/newPoint.test.js +117 -0
- package/plugins/draw/src/api/setStyle.js +43 -0
- package/plugins/draw/src/api/setStyle.test.js +75 -0
- package/plugins/draw/src/events.js +17 -10
- package/plugins/draw/src/events.test.js +14 -0
- package/plugins/draw/src/manifest.js +18 -6
- package/plugins/draw/src/manifest.test.js +32 -1
- package/plugins/draw/src/reducer.test.js +7 -0
- package/plugins/draw/src/utils/stripInternalProperties.js +19 -0
- package/plugins/draw/src/utils/stripInternalProperties.test.js +50 -0
- package/plugins/draw/src/utils/symbolKeys.js +5 -0
- package/plugins/draw/src/validation/liveDrawChecks.test.js +54 -0
- package/plugins/draw/src/validation/liveStroke.test.js +64 -1
- package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
- package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
- package/plugins/interact/dist/umd/index.js +1 -1
- package/plugins/interact/src/hooks/useHighlightSync.js +33 -12
- package/plugins/interact/src/hooks/useHighlightSync.test.js +96 -25
- package/plugins/interact/src/utils/featureQueries.js +18 -0
- package/plugins/interact/src/utils/featureQueries.test.js +15 -0
- package/plugins/interact/src/utils/spatial.js +9 -3
- package/plugins/interact/src/utils/spatial.test.js +12 -1
- package/plugins/map-key/dist/css/index.css +62 -0
- package/plugins/map-key/dist/esm/im-map-key-plugin.js +1 -0
- package/plugins/map-key/dist/esm/index.js +1 -0
- package/plugins/map-key/dist/umd/im-map-key-plugin.js +2 -0
- package/plugins/map-key/dist/umd/im-map-key-plugin.js.LICENSE.txt +1 -0
- package/plugins/map-key/dist/umd/index.js +2 -0
- package/plugins/map-key/dist/umd/index.js.LICENSE.txt +1 -0
- package/plugins/map-key/package.json +28 -0
- package/plugins/map-key/src/components/Key/EmptyKey.jsx +7 -0
- package/plugins/{datasets → map-key}/src/components/Key/EmptyKey.test.jsx +2 -2
- package/plugins/map-key/src/components/Key/Key.jsx +41 -0
- package/plugins/{datasets → map-key}/src/components/Key/Key.module.scss +15 -14
- package/plugins/map-key/src/components/Key/Key.test.jsx +73 -0
- package/plugins/map-key/src/components/Key/KeyGroupItem.jsx +16 -0
- package/plugins/map-key/src/components/Key/KeyGroupItem.test.jsx +53 -0
- package/plugins/map-key/src/components/Key/KeyItem.jsx +29 -0
- package/plugins/map-key/src/components/Key/KeyItem.test.jsx +67 -0
- package/plugins/map-key/src/components/Key/KeySvg.jsx +42 -0
- package/plugins/{datasets → map-key}/src/components/Key/KeySvg.test.jsx +14 -12
- package/plugins/map-key/src/components/Key/KeySvgLine.jsx +28 -0
- package/plugins/{datasets → map-key}/src/components/Key/KeySvgLine.test.jsx +1 -1
- package/plugins/map-key/src/components/Key/KeySvgPattern.jsx +23 -0
- package/plugins/{datasets → map-key}/src/components/Key/KeySvgPattern.test.jsx +2 -2
- package/plugins/map-key/src/components/Key/KeySvgRect.jsx +33 -0
- package/plugins/{datasets → map-key}/src/components/Key/KeySvgRect.test.jsx +1 -1
- package/plugins/map-key/src/components/Key/KeySvgSymbol.jsx +27 -0
- package/plugins/{datasets → map-key}/src/components/Key/KeySvgSymbol.test.jsx +5 -6
- package/plugins/map-key/src/components/Key/MapKey.jsx +50 -0
- package/plugins/map-key/src/components/Key/MapKey.test.jsx +130 -0
- package/plugins/{datasets → map-key}/src/components/Key/svgProperties.js +2 -2
- package/plugins/{datasets → map-key}/src/components/Key/svgProperties.test.js +2 -2
- package/plugins/map-key/src/index.js +13 -0
- package/plugins/map-key/src/index.test.js +31 -0
- package/plugins/map-key/src/initialise/MapKeyInit.jsx +15 -0
- package/plugins/map-key/src/initialise/MapKeyInit.test.jsx +39 -0
- package/plugins/map-key/src/manifest.js +30 -0
- package/plugins/map-key/src/manifest.test.js +63 -0
- package/plugins/map-key/src/mapKey.scss +4 -0
- package/plugins/map-key/src/registry/getDatasetRegistry.js +6 -0
- package/plugins/map-key/src/registry/getDatasetRegistry.test.js +23 -0
- package/plugins/map-key/src/registry/index.js +3 -0
- package/plugins/map-key/src/registry/index.test.js +15 -0
- package/plugins/menu/dist/css/index.css +80 -0
- package/plugins/menu/dist/esm/im-menu-plugin.js +1 -0
- package/plugins/menu/dist/esm/index.js +1 -0
- package/plugins/menu/dist/umd/im-menu-plugin.js +1 -0
- package/plugins/menu/dist/umd/index.js +2 -0
- package/plugins/menu/dist/umd/index.js.LICENSE.txt +1 -0
- package/plugins/menu/package.json +28 -0
- package/plugins/menu/src/components/Menu/CheckboxGroupWrapper.jsx +21 -0
- package/plugins/menu/src/components/Menu/GroupLegend.jsx +17 -0
- package/plugins/menu/src/components/Menu/GroupLegend.test.jsx +68 -0
- package/plugins/menu/src/components/Menu/Menu.jsx +19 -0
- package/plugins/menu/src/components/Menu/Menu.module.scss +90 -0
- package/plugins/menu/src/components/Menu/Menu.test.jsx +161 -0
- package/plugins/menu/src/components/Menu/MenuCheckbox.jsx +35 -0
- package/plugins/menu/src/components/Menu/MenuCheckbox.test.jsx +93 -0
- package/plugins/menu/src/components/Menu/MenuGroup.jsx +11 -0
- package/plugins/{datasets/src/components/LayersMenu/LayersMenuRadio.jsx → menu/src/components/Menu/MenuRadio.jsx} +6 -4
- package/plugins/{datasets/src/components/LayersMenu/LayersMenuRadio.test.jsx → menu/src/components/Menu/MenuRadio.test.jsx} +18 -18
- package/plugins/menu/src/components/Menu/RadioGroupWrapper.jsx +32 -0
- package/plugins/{datasets/src/components/LayersMenu/LayersRadioGroupWrapper.test.jsx → menu/src/components/Menu/RadioGroupWrapper.test.jsx} +21 -21
- package/plugins/menu/src/components/Menu/useIdPrefix.jsx +4 -0
- package/plugins/menu/src/index.js +13 -0
- package/plugins/menu/src/index.test.js +31 -0
- package/plugins/menu/src/initialise/MenuInit.jsx +24 -0
- package/plugins/menu/src/initialise/MenuInit.test.jsx +50 -0
- package/plugins/menu/src/initialise/createMenu.js +10 -0
- package/plugins/menu/src/initialise/createMenu.test.js +37 -0
- package/plugins/menu/src/manifest.js +35 -0
- package/plugins/menu/src/manifest.test.js +63 -0
- package/plugins/menu/src/menu.scss +4 -0
- package/plugins/menu/src/reducers/menuStateReducer.test.js +38 -0
- package/plugins/menu/src/reducers/pluginState.js +35 -0
- package/plugins/menu/src/reducers/pluginState.test.js +57 -0
- package/plugins/menu/src/registry/getDatasetRegistry.js +9 -0
- package/plugins/menu/src/registry/getDatasetRegistry.test.js +23 -0
- package/plugins/menu/src/registry/index.js +3 -0
- package/plugins/menu/src/registry/index.test.js +15 -0
- package/plugins/menu/src/registry/isVisibleWhen.js +43 -0
- package/plugins/menu/src/registry/isVisibleWhen.test.js +48 -0
- package/plugins/search/dist/css/index.css +1 -1
- package/plugins/search/dist/esm/im-search-plugin.js +1 -1
- package/plugins/search/dist/esm/index.js +1 -1
- package/plugins/search/dist/umd/im-search-plugin.js +1 -1
- package/plugins/search/dist/umd/index.js +1 -1
- package/plugins/search/src/Search.jsx +2 -3
- package/plugins/search/src/components/Form/Form.module.scss +9 -20
- package/plugins/search/src/index.js +0 -1
- package/plugins/search/src/index.test.js +2 -4
- package/plugins/search/src/manifest.js +1 -1
- package/plugins/search/src/search.scss +17 -16
- package/providers/beta/openlayers/dist/esm/im-openlayers-provider.js +1 -1
- package/providers/beta/openlayers/dist/umd/im-openlayers-provider.js +1 -1
- package/providers/beta/openlayers/dist/umd/index.js +1 -1
- package/providers/beta/openlayers/src/openlayersProvider.js +4 -1
- package/providers/beta/openlayers/src/openlayersProvider.test.js +18 -0
- package/providers/beta/openlayers/src/utils/highlightFeatures.js +52 -5
- package/providers/beta/openlayers/src/utils/highlightFeatures.test.js +176 -0
- package/providers/beta/openlayers/src/utils/symbolImages.js +40 -0
- package/providers/beta/openlayers/src/utils/symbolImages.test.js +58 -0
- package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
- package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
- package/providers/maplibre/dist/umd/index.js +1 -1
- package/providers/maplibre/src/utils/drawLayerBuckets.js +14 -0
- package/providers/maplibre/src/utils/drawLayerBuckets.test.js +18 -0
- package/providers/maplibre/src/utils/highlightFeatures.js +80 -55
- package/providers/maplibre/src/utils/highlightFeatures.test.js +156 -17
- package/providers/maplibre/src/utils/hoverCursor.js +30 -14
- package/providers/maplibre/src/utils/hoverCursor.test.js +35 -0
- package/providers/maplibre/src/utils/patternImages.js +1 -1
- package/providers/maplibre/src/utils/symbolImages.js +41 -3
- package/providers/maplibre/src/utils/symbolImages.test.js +40 -6
- package/rollup.esm.mjs +11 -1
- package/src/App/components/Actions/Actions.test.jsx +47 -0
- package/src/App/components/Hints/Hints.test.jsx +13 -0
- package/src/App/components/MoveControls/MoveControls.module.scss +41 -10
- package/src/App/components/Panel/Panel.jsx +18 -3
- package/src/App/components/Panel/Panel.module.scss +18 -8
- package/src/App/components/Panel/Panel.test.jsx +34 -0
- package/src/App/components/Tooltip/Tooltip.test.jsx +12 -14
- package/src/App/hooks/useFeatureItems.js +16 -7
- package/src/App/hooks/useFeatureItems.test.js +57 -0
- package/src/App/hooks/useLayoutMeasurements.js +95 -84
- package/src/App/hooks/useLayoutMeasurements.test.js +61 -1
- package/src/App/layout/Layout.jsx +9 -10
- package/src/App/layout/Layout.test.jsx +2 -0
- package/src/App/layout/layout.module.scss +31 -17
- package/src/App/registry/pluginRegistry.js +1 -1
- package/src/App/registry/pluginRegistry.test.js +12 -0
- package/src/App/renderer/HtmlElementHost.jsx +18 -5
- package/src/App/renderer/HtmlElementHost.test.jsx +54 -0
- package/src/App/renderer/mapButtons.js +28 -12
- package/src/App/renderer/mapButtons.test.js +17 -4
- package/src/App/renderer/mapControls.js +3 -1
- package/src/App/renderer/mapControls.test.js +16 -0
- package/src/App/renderer/mapPanels.js +44 -9
- package/src/App/renderer/mapPanels.test.js +51 -2
- package/src/App/renderer/orderItems.js +28 -0
- package/src/App/renderer/orderItems.test.js +50 -0
- package/src/App/renderer/slotAggregator.js +2 -18
- package/src/App/renderer/slotHelpers.js +3 -1
- package/src/App/renderer/slotHelpers.test.js +5 -0
- package/src/App/renderer/slots.js +3 -0
- package/src/App/store/AppProvider.jsx +1 -0
- package/src/App/store/appDispatchMiddleware.js +1 -1
- package/src/App/store/appDispatchMiddleware.test.js +8 -0
- package/src/config/events.js +2 -0
- package/src/scss/settings/_colors.scss +1 -0
- package/src/scss/settings/_dimensions.scss +2 -3
- package/src/scss/settings/_transition.scss +1 -1
- package/src/services/eventBus.js +44 -0
- package/src/services/eventBus.test.js +83 -0
- package/src/services/symbolRegistry.js +1 -1
- package/src/types.js +11 -1
- package/webpack.umd.mjs +2 -0
- package/plugins/datasets/src/components/Key/EmptyKey.jsx +0 -7
- package/plugins/datasets/src/components/Key/Key.jsx +0 -50
- package/plugins/datasets/src/components/Key/KeyGroupItem.jsx +0 -18
- package/plugins/datasets/src/components/Key/KeyItem.jsx +0 -23
- package/plugins/datasets/src/components/Key/KeySvg.jsx +0 -22
- package/plugins/datasets/src/components/Key/KeySvgLine.jsx +0 -19
- package/plugins/datasets/src/components/Key/KeySvgPattern.jsx +0 -13
- package/plugins/datasets/src/components/Key/KeySvgRect.jsx +0 -22
- package/plugins/datasets/src/components/Key/KeySvgSymbol.jsx +0 -16
- package/plugins/datasets/src/components/LayersMenu/LayersRadioGroupWrapper.jsx +0 -41
- /package/plugins/{datasets → menu}/src/reducers/menuStateReducer.js +0 -0
- /package/{providers/maplibre/src → src}/utils/rasteriseToImageData.js +0 -0
- /package/{providers/maplibre/src → src}/utils/rasteriseToImageData.test.js +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createMapboxDraw } from './mapboxDraw.js'
|
|
2
2
|
import { getSnapInstance, clearSnapState, clearSnapIndicator } from './utils/snapHelpers.js'
|
|
3
3
|
import { createEventBus } from '../../utils/eventBus.js'
|
|
4
|
+
import { resolvePointSymbol, hasSymbolStyle } from './pointSymbolImages.js'
|
|
4
5
|
import { MAPBOX_DRAW_EVENTS, CUSTOM_DRAW_EVENTS, STYLE_DATA_EVENT } from './drawEvents.js'
|
|
5
6
|
import { MaplibreDrawAdapter, displayedShape } from './MaplibreDrawAdapter.js'
|
|
6
7
|
|
|
@@ -11,6 +12,11 @@ jest.mock('./utils/snapHelpers.js', () => ({
|
|
|
11
12
|
clearSnapIndicator: jest.fn()
|
|
12
13
|
}))
|
|
13
14
|
jest.mock('../../utils/eventBus.js', () => ({ createEventBus: jest.fn() }))
|
|
15
|
+
jest.mock('./pointSymbolImages.js', () => ({
|
|
16
|
+
resolvePointSymbol: jest.fn(),
|
|
17
|
+
refreshAllPointSymbols: jest.fn(),
|
|
18
|
+
hasSymbolStyle: jest.fn()
|
|
19
|
+
}))
|
|
14
20
|
|
|
15
21
|
const SNAP_LAYER = 'snap-helper-circle'
|
|
16
22
|
|
|
@@ -112,19 +118,61 @@ describe('construction', () => {
|
|
|
112
118
|
})
|
|
113
119
|
|
|
114
120
|
describe('map event normalisation', () => {
|
|
115
|
-
test('
|
|
121
|
+
test('editfinish/update forward the first feature', () => {
|
|
116
122
|
const { map, bus } = setup()
|
|
117
123
|
const feature = { id: 'f1' }
|
|
118
124
|
|
|
119
|
-
onHandler(map, MAPBOX_DRAW_EVENTS.CREATE)({ features: [feature] })
|
|
120
125
|
onHandler(map, CUSTOM_DRAW_EVENTS.EDIT_FINISH)({ features: [feature] })
|
|
121
126
|
onHandler(map, MAPBOX_DRAW_EVENTS.UPDATE)({ features: [feature] })
|
|
122
127
|
|
|
123
|
-
expect(bus.emit).toHaveBeenCalledWith('create', feature)
|
|
124
128
|
expect(bus.emit).toHaveBeenCalledWith('editfinish', feature)
|
|
125
129
|
expect(bus.emit).toHaveBeenCalledWith('update', feature)
|
|
126
130
|
})
|
|
127
131
|
|
|
132
|
+
// Drives fill/line/symbol-sort-key (styles.js) — a feature drawn interactively (not via the
|
|
133
|
+
// add() API) still needs a sort key assigned exactly once, at the point it's actually created.
|
|
134
|
+
// Deferred a tick: the owning draw mode's own 'draw.create' listener re-ids the feature to its
|
|
135
|
+
// final id in the same synchronous dispatch (see drawPointMode.js/clickHandlers.js), and this
|
|
136
|
+
// handler must run after that re-id, not before it.
|
|
137
|
+
test('create assigns an incrementing sortKey via setFeatureProperty before forwarding, after the mode\'s own re-id has run', () => {
|
|
138
|
+
jest.useFakeTimers()
|
|
139
|
+
const { map, draw, bus } = setup()
|
|
140
|
+
draw.get.mockImplementation((id) => ({ id, properties: { sortKey: id === 'f1' ? 1 : 2 } }))
|
|
141
|
+
|
|
142
|
+
onHandler(map, MAPBOX_DRAW_EVENTS.CREATE)({ features: [{ id: 'f1' }] })
|
|
143
|
+
onHandler(map, MAPBOX_DRAW_EVENTS.CREATE)({ features: [{ id: 'f2' }] })
|
|
144
|
+
expect(draw.setFeatureProperty).not.toHaveBeenCalled() // deferred past the mode's re-id
|
|
145
|
+
jest.runAllTimers()
|
|
146
|
+
|
|
147
|
+
expect(draw.setFeatureProperty).toHaveBeenNthCalledWith(1, 'f1', 'sortKey', 1)
|
|
148
|
+
expect(draw.setFeatureProperty).toHaveBeenNthCalledWith(2, 'f2', 'sortKey', 2)
|
|
149
|
+
// Forwards the freshly re-fetched feature (carrying the new property), not the stale event payload.
|
|
150
|
+
expect(bus.emit).toHaveBeenCalledWith('create', { id: 'f1', properties: { sortKey: 1 } })
|
|
151
|
+
expect(bus.emit).toHaveBeenCalledWith('create', { id: 'f2', properties: { sortKey: 2 } })
|
|
152
|
+
jest.useRealTimers()
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
// Reproduces the real integration hazard the deferral above guards against: a draw mode's
|
|
156
|
+
// 'draw.create' listener re-ids the feature (mutating the SAME event payload object) in the
|
|
157
|
+
// same synchronous dispatch, before this handler's deferred callback runs.
|
|
158
|
+
test('create picks up a feature id re-assigned synchronously by the owning draw mode', () => {
|
|
159
|
+
jest.useFakeTimers()
|
|
160
|
+
const { map, draw, bus } = setup()
|
|
161
|
+
draw.get.mockImplementation((id) => ({ id, properties: { sortKey: 1 } }))
|
|
162
|
+
const feature = { id: 'mapbox-temp-id' }
|
|
163
|
+
|
|
164
|
+
onHandler(map, MAPBOX_DRAW_EVENTS.CREATE)({ features: [feature] })
|
|
165
|
+
// Simulate the owning draw mode's own 'draw.create' listener re-idding this SAME feature
|
|
166
|
+
// object, synchronously, later in the same dispatch — before this handler's deferred
|
|
167
|
+
// callback below runs.
|
|
168
|
+
feature.id = 'caller-requested-id'
|
|
169
|
+
jest.runAllTimers()
|
|
170
|
+
|
|
171
|
+
expect(draw.setFeatureProperty).toHaveBeenCalledWith('caller-requested-id', 'sortKey', 1)
|
|
172
|
+
expect(bus.emit).toHaveBeenCalledWith('create', { id: 'caller-requested-id', properties: { sortKey: 1 } })
|
|
173
|
+
jest.useRealTimers()
|
|
174
|
+
})
|
|
175
|
+
|
|
128
176
|
test('cancel forwards with no payload', () => {
|
|
129
177
|
const { map, bus } = setup()
|
|
130
178
|
onHandler(map, CUSTOM_DRAW_EVENTS.CANCEL)()
|
|
@@ -184,9 +232,41 @@ describe('displayedShape helper', () => {
|
|
|
184
232
|
expect(line?.feature?.geometry?.type).toBe('LineString')
|
|
185
233
|
})
|
|
186
234
|
|
|
235
|
+
test('builds a point feature from edit_point mode, with a flat (unnested) coordinate', () => {
|
|
236
|
+
const result = displayedShape('edit_point', [5, 5])
|
|
237
|
+
expect(result?.feature?.type).toBe('Feature')
|
|
238
|
+
expect(result?.feature?.geometry).toEqual({ type: 'Point', coordinates: [5, 5] })
|
|
239
|
+
expect(result?.numVertices).toBe(1)
|
|
240
|
+
})
|
|
241
|
+
|
|
187
242
|
test('returns null for an unknown mode', () => {
|
|
188
243
|
expect(displayedShape('unknown_mode', [[0, 0], [10, 0]])).toBeNull()
|
|
189
244
|
})
|
|
245
|
+
|
|
246
|
+
// A ring/coordinate array can transiently be empty/absent right as a sketch starts —
|
|
247
|
+
// the `?? …` fallbacks keep numVertices a sane number instead of crashing on `undefined.length`.
|
|
248
|
+
test('falls back to numVertices 0 for a draw_polygon sketch with no ring yet', () => {
|
|
249
|
+
expect(displayedShape('draw_polygon', [])?.numVertices).toBe(0)
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
test('falls back to numVertices 0 for a draw_line sketch with no coordinates yet', () => {
|
|
253
|
+
expect(displayedShape('draw_line', undefined)?.numVertices).toBe(0)
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
test('falls back to numVertices 0 for an edit_vertex polygon with no ring yet', () => {
|
|
257
|
+
const result = displayedShape('edit_vertex', [])
|
|
258
|
+
expect(result?.feature?.geometry?.type).toBe('LineString') // coordinates[0] undefined → not detected as a polygon ring
|
|
259
|
+
expect(result?.numVertices).toBe(0)
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
// A plain object (not an array) still satisfies edit_vertex's own coordinates[0]?.[0]
|
|
263
|
+
// access without throwing, but has no .length of its own — the line branch's `?? 0`
|
|
264
|
+
// fallback the case above can't reach (an empty array's .length is 0, not nullish).
|
|
265
|
+
test('falls back to numVertices 0 for an edit_vertex line whose coordinates have no length at all', () => {
|
|
266
|
+
const result = displayedShape('edit_vertex', {})
|
|
267
|
+
expect(result?.feature?.geometry?.type).toBe('LineString')
|
|
268
|
+
expect(result?.numVertices).toBe(0)
|
|
269
|
+
})
|
|
190
270
|
})
|
|
191
271
|
|
|
192
272
|
describe('live invalid stroke (draw mode)', () => {
|
|
@@ -338,6 +418,18 @@ describe('live invalid stroke (edit mode)', () => {
|
|
|
338
418
|
expect(bus.emit).not.toHaveBeenCalledWith('canplacechange', expect.anything())
|
|
339
419
|
})
|
|
340
420
|
|
|
421
|
+
test('validity flips also gate the Done button while editing a point', () => {
|
|
422
|
+
jest.useFakeTimers()
|
|
423
|
+
const { map, draw, bus } = editSetup()
|
|
424
|
+
draw.getMode.mockReturnValue('edit_point')
|
|
425
|
+
const fire = onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)
|
|
426
|
+
map._drawGeometryValidator = () => ({ valid: false, reason: 'outside region' })
|
|
427
|
+
fire({ type: 'draw.geometrychange', coordinates: [5, 5] })
|
|
428
|
+
jest.runAllTimers()
|
|
429
|
+
expect(bus.emit).toHaveBeenCalledWith('validitychange', expect.objectContaining({ valid: false, reason: 'outside region' }))
|
|
430
|
+
jest.useRealTimers()
|
|
431
|
+
})
|
|
432
|
+
|
|
341
433
|
test('lines never go dashed from the default rules while editing', () => {
|
|
342
434
|
const { map } = editSetup()
|
|
343
435
|
onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)({ type: 'draw.geometrychange', coordinates: [[0, 0], [10, 10], [10, 0], [0, 10]] })
|
|
@@ -376,6 +468,12 @@ describe('changeMode', () => {
|
|
|
376
468
|
expect(draw.changeMode).toHaveBeenCalledWith('edit_vertex', { featureId: 'f9' })
|
|
377
469
|
})
|
|
378
470
|
|
|
471
|
+
test('records the editing feature id when entering edit_point', () => {
|
|
472
|
+
const { adapter, draw } = setup()
|
|
473
|
+
adapter.changeMode('edit_point', { featureId: 'f9' })
|
|
474
|
+
expect(draw.changeMode).toHaveBeenCalledWith('edit_point', { featureId: 'f9' })
|
|
475
|
+
})
|
|
476
|
+
|
|
379
477
|
test('defaults the editing feature id to null when omitted', () => {
|
|
380
478
|
const { adapter, draw } = setup()
|
|
381
479
|
adapter.changeMode('edit_vertex', {})
|
|
@@ -390,6 +488,20 @@ describe('changeMode', () => {
|
|
|
390
488
|
adapter.changeMode('draw_polygon')
|
|
391
489
|
expect(draw.changeMode).toHaveBeenCalledWith('draw_polygon', {})
|
|
392
490
|
})
|
|
491
|
+
|
|
492
|
+
test('draw_point gets a resolvePointSymbol hook injected, delegating to pointSymbolImages.js', () => {
|
|
493
|
+
const { adapter, draw, map, mapProvider } = setup()
|
|
494
|
+
adapter.changeMode('draw_point', { featureId: 'p1' })
|
|
495
|
+
|
|
496
|
+
expect(draw.changeMode).toHaveBeenCalledWith('draw_point', {
|
|
497
|
+
featureId: 'p1',
|
|
498
|
+
resolvePointSymbol: expect.any(Function)
|
|
499
|
+
})
|
|
500
|
+
|
|
501
|
+
const injected = draw.changeMode.mock.calls[0][1].resolvePointSymbol
|
|
502
|
+
injected('p1', { symbol: 'pin' })
|
|
503
|
+
expect(resolvePointSymbol).toHaveBeenCalledWith({ draw, mapProvider, map, featureId: 'p1', properties: { symbol: 'pin' } })
|
|
504
|
+
})
|
|
393
505
|
})
|
|
394
506
|
|
|
395
507
|
describe('setGeometryValid', () => {
|
|
@@ -486,12 +598,122 @@ describe('simple delegations', () => {
|
|
|
486
598
|
adapter.setFeatureProperty('d', 'p', 1)
|
|
487
599
|
|
|
488
600
|
expect(draw.get).toHaveBeenCalledWith('a')
|
|
489
|
-
expect(draw.add).toHaveBeenCalledWith({ id: 'b' })
|
|
601
|
+
expect(draw.add).toHaveBeenCalledWith({ id: 'b', properties: { sortKey: 1 } })
|
|
490
602
|
expect(draw.delete).toHaveBeenCalledWith('c')
|
|
491
603
|
expect(draw.deleteAll).toHaveBeenCalled()
|
|
492
604
|
expect(draw.setFeatureProperty).toHaveBeenCalledWith('d', 'p', 1)
|
|
493
605
|
})
|
|
494
606
|
|
|
607
|
+
// A directly-added Point skips draw_point's own icon-resolving drawend handler.
|
|
608
|
+
describe('add() and point symbol resolution', () => {
|
|
609
|
+
test('resolves the symbol for a Point feature with symbol properties, using the id draw.add() returns', () => {
|
|
610
|
+
const { adapter, draw, map, mapProvider } = setup()
|
|
611
|
+
draw.add.mockReturnValue(['generated-id'])
|
|
612
|
+
hasSymbolStyle.mockReturnValue(true)
|
|
613
|
+
const feature = { geometry: { type: 'Point', coordinates: [0, 0] }, properties: { symbol: 'pin' } }
|
|
614
|
+
|
|
615
|
+
const result = adapter.add(feature)
|
|
616
|
+
|
|
617
|
+
expect(hasSymbolStyle).toHaveBeenCalledWith({ symbol: 'pin', sortKey: 1 })
|
|
618
|
+
expect(resolvePointSymbol).toHaveBeenCalledWith({
|
|
619
|
+
draw, mapProvider, map, featureId: 'generated-id', properties: { symbol: 'pin', sortKey: 1 }
|
|
620
|
+
})
|
|
621
|
+
expect(result).toEqual(['generated-id'])
|
|
622
|
+
})
|
|
623
|
+
|
|
624
|
+
test('does not attempt resolution for a Point with no symbol properties', () => {
|
|
625
|
+
const { adapter, draw } = setup()
|
|
626
|
+
draw.add.mockReturnValue(['id-1'])
|
|
627
|
+
hasSymbolStyle.mockReturnValue(false)
|
|
628
|
+
adapter.add({ geometry: { type: 'Point', coordinates: [0, 0] }, properties: {} })
|
|
629
|
+
expect(resolvePointSymbol).not.toHaveBeenCalled()
|
|
630
|
+
})
|
|
631
|
+
|
|
632
|
+
test('does not attempt resolution for a non-Point geometry', () => {
|
|
633
|
+
const { adapter, draw } = setup()
|
|
634
|
+
draw.add.mockReturnValue(['id-1'])
|
|
635
|
+
adapter.add({ geometry: { type: 'Polygon', coordinates: [[]] }, properties: { symbol: 'pin' } })
|
|
636
|
+
expect(hasSymbolStyle).not.toHaveBeenCalled()
|
|
637
|
+
expect(resolvePointSymbol).not.toHaveBeenCalled()
|
|
638
|
+
})
|
|
639
|
+
|
|
640
|
+
test('does not attempt resolution for a feature with no geometry', () => {
|
|
641
|
+
const { adapter, draw } = setup()
|
|
642
|
+
draw.add.mockReturnValue(['id-1'])
|
|
643
|
+
adapter.add({ id: 'b' })
|
|
644
|
+
expect(resolvePointSymbol).not.toHaveBeenCalled()
|
|
645
|
+
})
|
|
646
|
+
})
|
|
647
|
+
|
|
648
|
+
describe('add() sort key assignment', () => {
|
|
649
|
+
test('assigns an incrementing sortKey to each genuinely new feature', () => {
|
|
650
|
+
const { adapter, draw } = setup()
|
|
651
|
+
adapter.add({ id: 'a' })
|
|
652
|
+
adapter.add({ id: 'b' })
|
|
653
|
+
expect(draw.add).toHaveBeenNthCalledWith(1, { id: 'a', properties: { sortKey: 1 } })
|
|
654
|
+
expect(draw.add).toHaveBeenNthCalledWith(2, { id: 'b', properties: { sortKey: 2 } })
|
|
655
|
+
})
|
|
656
|
+
|
|
657
|
+
test('preserves an existing sortKey rather than assigning a new one', () => {
|
|
658
|
+
const { adapter, draw } = setup()
|
|
659
|
+
adapter.add({ id: 'a', properties: { sortKey: 5 } })
|
|
660
|
+
expect(draw.add).toHaveBeenCalledWith({ id: 'a', properties: { sortKey: 5 } })
|
|
661
|
+
})
|
|
662
|
+
})
|
|
663
|
+
|
|
664
|
+
describe('setStyle()', () => {
|
|
665
|
+
test('merges the patch into the existing feature and re-adds it', () => {
|
|
666
|
+
const { adapter, draw } = setup()
|
|
667
|
+
const feature = { id: 'a', type: 'Feature', geometry: { type: 'Polygon', coordinates: [[]] }, properties: { stroke: 'red', name: 'x' } }
|
|
668
|
+
draw.get.mockReturnValue(feature)
|
|
669
|
+
draw.add.mockReturnValue(['a'])
|
|
670
|
+
|
|
671
|
+
adapter.setStyle('a', { stroke: 'blue' })
|
|
672
|
+
|
|
673
|
+
expect(draw.add).toHaveBeenCalledWith({
|
|
674
|
+
id: 'a',
|
|
675
|
+
type: 'Feature',
|
|
676
|
+
geometry: { type: 'Polygon', coordinates: [[]] },
|
|
677
|
+
properties: { stroke: 'blue', name: 'x', sortKey: 1 }
|
|
678
|
+
})
|
|
679
|
+
})
|
|
680
|
+
|
|
681
|
+
test('preserves an existing sortKey rather than assigning a new one', () => {
|
|
682
|
+
const { adapter, draw } = setup()
|
|
683
|
+
const feature = { id: 'a', type: 'Feature', geometry: { type: 'Polygon', coordinates: [[]] }, properties: { stroke: 'red', sortKey: 7 } }
|
|
684
|
+
draw.get.mockReturnValue(feature)
|
|
685
|
+
draw.add.mockReturnValue(['a'])
|
|
686
|
+
|
|
687
|
+
adapter.setStyle('a', { stroke: 'blue' })
|
|
688
|
+
|
|
689
|
+
expect(draw.add).toHaveBeenCalledWith(expect.objectContaining({ properties: { stroke: 'blue', sortKey: 7 } }))
|
|
690
|
+
})
|
|
691
|
+
|
|
692
|
+
// setStyle is routed through add() itself, so a Point patched with symbol properties gets
|
|
693
|
+
// its icon re-resolved the same way a directly-added one does.
|
|
694
|
+
test('re-resolves the icon for a Point patched with symbol properties', () => {
|
|
695
|
+
const { adapter, draw } = setup()
|
|
696
|
+
const feature = { id: 'p1', type: 'Feature', geometry: { type: 'Point', coordinates: [0, 0] }, properties: { symbol: 'pin' } }
|
|
697
|
+
draw.get.mockReturnValue(feature)
|
|
698
|
+
draw.add.mockReturnValue(['p1'])
|
|
699
|
+
hasSymbolStyle.mockReturnValue(true)
|
|
700
|
+
|
|
701
|
+
adapter.setStyle('p1', { symbolBackgroundColor: '#ca3535' })
|
|
702
|
+
|
|
703
|
+
expect(resolvePointSymbol).toHaveBeenCalledWith(expect.objectContaining({
|
|
704
|
+
featureId: 'p1',
|
|
705
|
+
properties: { symbol: 'pin', symbolBackgroundColor: '#ca3535', sortKey: 1 }
|
|
706
|
+
}))
|
|
707
|
+
})
|
|
708
|
+
|
|
709
|
+
test('does nothing for an id with no existing feature', () => {
|
|
710
|
+
const { adapter, draw } = setup()
|
|
711
|
+
draw.get.mockReturnValue(undefined)
|
|
712
|
+
adapter.setStyle('missing', { stroke: 'blue' })
|
|
713
|
+
expect(draw.add).not.toHaveBeenCalled()
|
|
714
|
+
})
|
|
715
|
+
})
|
|
716
|
+
|
|
495
717
|
test('setDrawingPreviewProperty tags the in-progress feature and re-renders', () => {
|
|
496
718
|
const { adapter, map } = setup()
|
|
497
719
|
const render = jest.fn()
|
|
@@ -570,6 +792,18 @@ describe('done', () => {
|
|
|
570
792
|
expect(map.fire).not.toHaveBeenCalled()
|
|
571
793
|
expect(draw.changeMode).not.toHaveBeenCalled()
|
|
572
794
|
})
|
|
795
|
+
|
|
796
|
+
test('clears the undo stack and fires editfinish when editing a point', () => {
|
|
797
|
+
const { adapter, map, draw, undoStack } = setup()
|
|
798
|
+
adapter.changeMode('edit_point', { featureId: 'f1' })
|
|
799
|
+
draw.getMode.mockReturnValue('edit_point')
|
|
800
|
+
|
|
801
|
+
adapter.done()
|
|
802
|
+
|
|
803
|
+
expect(undoStack.clear).toHaveBeenCalled()
|
|
804
|
+
expect(map.fire).toHaveBeenCalledWith(CUSTOM_DRAW_EVENTS.EDIT_FINISH, { features: [{ id: 'f1' }] })
|
|
805
|
+
expect(draw.changeMode).not.toHaveBeenCalledWith('disabled')
|
|
806
|
+
})
|
|
573
807
|
})
|
|
574
808
|
|
|
575
809
|
describe('cancel', () => {
|
|
@@ -719,6 +953,14 @@ describe('_handleModeChange', () => {
|
|
|
719
953
|
})
|
|
720
954
|
|
|
721
955
|
describe('_handleStyleData', () => {
|
|
956
|
+
test('does nothing when the map has no style yet (removed, or mid-teardown)', () => {
|
|
957
|
+
const { map } = setup()
|
|
958
|
+
map.getStyle.mockReturnValue(undefined)
|
|
959
|
+
expect(() => onHandler(map, STYLE_DATA_EVENT)()).not.toThrow()
|
|
960
|
+
expect(map.moveLayer).not.toHaveBeenCalled()
|
|
961
|
+
expect(map.setLayoutProperty).not.toHaveBeenCalled()
|
|
962
|
+
})
|
|
963
|
+
|
|
722
964
|
test('does nothing when there are no layers', () => {
|
|
723
965
|
const { map } = setup()
|
|
724
966
|
map.getStyle.mockReturnValue({ layers: undefined })
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import MapboxDraw from '@mapbox/mapbox-gl-draw'
|
|
2
2
|
import { DisabledMode } from './modes/disabledMode.js'
|
|
3
3
|
import { EditVertexMode } from './modes/editVertexMode.js'
|
|
4
|
+
import { EditPointMode } from './modes/editPointMode.js'
|
|
4
5
|
import { DrawPolygonMode } from './modes/drawPolygonMode.js'
|
|
5
6
|
import { DrawLineMode } from './modes/drawLineMode.js'
|
|
7
|
+
import { DrawPointMode } from './modes/drawPointMode.js'
|
|
6
8
|
import { createDrawStyles, updateDrawStyles } from './styles.js'
|
|
7
9
|
import { initMapLibreSnap } from './mapboxSnap.js'
|
|
8
10
|
import { createUndoStack } from '../../utils/undoStack.js'
|
|
@@ -10,6 +12,89 @@ import { setupTouchClickWorkaround } from './utils/touchClickWorkaround.js'
|
|
|
10
12
|
import { applyTouchVertexColors } from './modes/editVertexMode/touchHandlers.js'
|
|
11
13
|
import { resolveColors } from '../../utils/resolveColors.js'
|
|
12
14
|
import { TOLERANCES, MAP_SIZE_SCALES } from './defaults.js'
|
|
15
|
+
import { refreshAllPointSymbols } from './pointSymbolImages.js'
|
|
16
|
+
|
|
17
|
+
// map.setStyle() discards MapLibre's entire previous Style, wiping every programmatically
|
|
18
|
+
// added source/layer/image — including mapbox-gl-draw's own, which it never re-adds itself.
|
|
19
|
+
// draw.options.styles already holds the fully processed cold+hot layer pairs, so re-adding
|
|
20
|
+
// needs no new computation.
|
|
21
|
+
const DRAW_SOURCES = { COLD: 'mapbox-gl-draw-cold', HOT: 'mapbox-gl-draw-hot' }
|
|
22
|
+
|
|
23
|
+
// Re-creates the (empty) sources/layers only — deliberately doesn't push draw.getAll() back
|
|
24
|
+
// in here. mapbox-gl-draw's own render() is requestAnimationFrame-debounced, so doing that
|
|
25
|
+
// too early would write each point's *previous* (not yet re-resolved) image ids into the
|
|
26
|
+
// fresh source, racing the correct write that refreshAllPointSymbols makes moments later.
|
|
27
|
+
// The caller pushes the final data back in exactly once, after that settles.
|
|
28
|
+
const ensureDrawSourcesAndLayers = (map, draw) => {
|
|
29
|
+
if (map.getSource(DRAW_SOURCES.COLD)) {
|
|
30
|
+
return false // survived (or already restored) — nothing to do
|
|
31
|
+
}
|
|
32
|
+
const empty = { type: 'FeatureCollection', features: [] }
|
|
33
|
+
map.addSource(DRAW_SOURCES.COLD, { data: empty, type: 'geojson' })
|
|
34
|
+
map.addSource(DRAW_SOURCES.HOT, { data: empty, type: 'geojson' })
|
|
35
|
+
draw.options.styles.forEach(style => map.addLayer(style))
|
|
36
|
+
return true
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Reacts to MAP_STYLE_CHANGE (fired off the native 'style.load' event, i.e. after setStyle()
|
|
40
|
+
// actually ran), not MAP_SET_STYLE (fired the instant a change is *requested*, before setStyle
|
|
41
|
+
// may have run) — registering map.once('idle', ...) too early can catch the map still idle
|
|
42
|
+
// from the *previous* style and consume itself before the real wipe happens.
|
|
43
|
+
const settleStyleChange = ({ map, draw, mapProvider, pluginConfig, onDone }) => {
|
|
44
|
+
const mapStyle = map._drawCurrentMapStyle
|
|
45
|
+
map.once('idle', () => {
|
|
46
|
+
const sourcesWereMissing = ensureDrawSourcesAndLayers(map, draw)
|
|
47
|
+
updateDrawStyles(map, mapStyle, pluginConfig)
|
|
48
|
+
const svg = map._drawEditContainer?.querySelector('[data-im-draw-touch-target]')
|
|
49
|
+
applyTouchVertexColors(svg, mapStyle, pluginConfig)
|
|
50
|
+
// Rasterised point symbol images are style-scoped (colours resolve per map style) —
|
|
51
|
+
// re-resolve every drawn point's icon now the new style has settled.
|
|
52
|
+
refreshAllPointSymbols({ draw, mapProvider, map }).then(() => {
|
|
53
|
+
if (sourcesWereMissing) {
|
|
54
|
+
// draw's own feature store still holds everything; push it back now the new style's
|
|
55
|
+
// image ids are resolved — exactly one write, with final data.
|
|
56
|
+
draw.set(draw.getAll())
|
|
57
|
+
}
|
|
58
|
+
// The highlight ring is a standalone layer maintained outside mapbox-gl-draw's own
|
|
59
|
+
// render cycle, so nothing guarantees MapLibre repaints it (or refreshes the hover
|
|
60
|
+
// cursor's queryRenderedFeatures results) right after a style reload — force it.
|
|
61
|
+
map.triggerRepaint()
|
|
62
|
+
onDone()
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Wires MAP_SET_STYLE (stashes the incoming style) and MAP_STYLE_CHANGE (settles it) onto the
|
|
68
|
+
// event bus. Returns both handlers so createMapboxDraw's remove() can unsubscribe them.
|
|
69
|
+
const wireStyleChangeHandling = ({ map, draw, mapProvider, pluginConfig, eventBus, events, notifyPointSymbolsRefreshed }) => {
|
|
70
|
+
const handleSetMapStyle = (e) => {
|
|
71
|
+
map._drawCurrentMapStyle = e
|
|
72
|
+
}
|
|
73
|
+
eventBus.on(events.MAP_SET_STYLE, handleSetMapStyle)
|
|
74
|
+
|
|
75
|
+
// MAP_STYLE_CHANGE fires twice per style change (two separate 'style.load' listeners
|
|
76
|
+
// elsewhere in the app) — this guard stops settleStyleChange's expensive work running twice.
|
|
77
|
+
let settlePending = false
|
|
78
|
+
const handleStyleChanged = () => {
|
|
79
|
+
if (settlePending) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
settlePending = true
|
|
83
|
+
settleStyleChange({
|
|
84
|
+
map,
|
|
85
|
+
draw,
|
|
86
|
+
mapProvider,
|
|
87
|
+
pluginConfig,
|
|
88
|
+
onDone: () => {
|
|
89
|
+
settlePending = false
|
|
90
|
+
notifyPointSymbolsRefreshed()
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
eventBus.on(events.MAP_STYLE_CHANGE, handleStyleChanged)
|
|
95
|
+
|
|
96
|
+
return { handleSetMapStyle, handleStyleChanged }
|
|
97
|
+
}
|
|
13
98
|
|
|
14
99
|
/**
|
|
15
100
|
* Creates and manages a MapLibre/Mapbox Draw control instance configured for polygon editing.
|
|
@@ -40,8 +125,10 @@ export const createMapboxDraw = ({ mapStyle, mapProvider, events, eventBus, snap
|
|
|
40
125
|
...MapboxDraw.modes,
|
|
41
126
|
disabled: DisabledMode,
|
|
42
127
|
edit_vertex: EditVertexMode,
|
|
128
|
+
edit_point: EditPointMode,
|
|
43
129
|
draw_polygon: DrawPolygonMode,
|
|
44
|
-
draw_line: DrawLineMode
|
|
130
|
+
draw_line: DrawLineMode,
|
|
131
|
+
draw_point: DrawPointMode
|
|
45
132
|
}
|
|
46
133
|
|
|
47
134
|
// --- Create or reuse MapLibre Draw instance ---
|
|
@@ -67,10 +154,7 @@ export const createMapboxDraw = ({ mapStyle, mapProvider, events, eventBus, snap
|
|
|
67
154
|
// We need a reference to this
|
|
68
155
|
mapProvider.draw = draw
|
|
69
156
|
map._drawCurrentMapStyle = mapStyle
|
|
70
|
-
// Stashed on the map
|
|
71
|
-
// has `this.map` — e.g. touchHandlers.js's addTouchVertexTarget — can still
|
|
72
|
-
// resolve colour overrides without pluginConfig being threaded through every
|
|
73
|
-
// mode's option object.
|
|
157
|
+
// Stashed on the map so mode code with only `this.map` can resolve colour overrides.
|
|
74
158
|
map._drawPluginConfig = pluginConfig
|
|
75
159
|
// Initialize snap as disabled (matches initialState.snap = false)
|
|
76
160
|
mapProvider.snapEnabled = false
|
|
@@ -92,16 +176,14 @@ export const createMapboxDraw = ({ mapStyle, mapProvider, events, eventBus, snap
|
|
|
92
176
|
colors: { vertex: snapColors.snapVertex, edge: snapColors.snapEdge }
|
|
93
177
|
})
|
|
94
178
|
|
|
179
|
+
// Nudges plugins/interact's useHighlightSync to re-apply highlights once point symbols
|
|
180
|
+
// have actually finished re-resolving, rather than relying on a side-effect event.
|
|
181
|
+
const notifyPointSymbolsRefreshed = () => eventBus.emit(events.MAP_DATA_CHANGE)
|
|
182
|
+
|
|
95
183
|
// --- Update colour scheme ---
|
|
96
|
-
const handleSetMapStyle = (
|
|
97
|
-
map
|
|
98
|
-
|
|
99
|
-
updateDrawStyles(map, e, pluginConfig)
|
|
100
|
-
const svg = map._drawEditContainer?.querySelector('[data-im-draw-touch-target]')
|
|
101
|
-
applyTouchVertexColors(svg, e, pluginConfig)
|
|
102
|
-
})
|
|
103
|
-
}
|
|
104
|
-
eventBus.on(events.MAP_SET_STYLE, handleSetMapStyle)
|
|
184
|
+
const { handleSetMapStyle, handleStyleChanged } = wireStyleChangeHandling({
|
|
185
|
+
map, draw, mapProvider, pluginConfig, eventBus, events, notifyPointSymbolsRefreshed
|
|
186
|
+
})
|
|
105
187
|
|
|
106
188
|
// --- Update map scale ---
|
|
107
189
|
const handleSetMapSize = (e) => {
|
|
@@ -109,6 +191,17 @@ export const createMapboxDraw = ({ mapStyle, mapProvider, events, eventBus, snap
|
|
|
109
191
|
}
|
|
110
192
|
eventBus.on(events.MAP_SET_SIZE, handleSetMapSize)
|
|
111
193
|
|
|
194
|
+
// --- Update point symbol resolution for the new pixel ratio ---
|
|
195
|
+
// MAP_SET_PIXEL_RATIO carries the freshly computed pixel ratio itself, fired right after
|
|
196
|
+
// MAP_SET_SIZE — that's the value this needs, not map.getPixelRatio() (unchanged since init).
|
|
197
|
+
const handleSetPixelRatio = (pixelRatio) => {
|
|
198
|
+
refreshAllPointSymbols({ draw, mapProvider, map, pixelRatioOverride: pixelRatio }).then(() => {
|
|
199
|
+
map.triggerRepaint()
|
|
200
|
+
notifyPointSymbolsRefreshed()
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
eventBus.on(events.MAP_SET_PIXEL_RATIO, handleSetPixelRatio)
|
|
204
|
+
|
|
112
205
|
// --- Return instance and cleanup function ---
|
|
113
206
|
return {
|
|
114
207
|
draw,
|
|
@@ -116,7 +209,9 @@ export const createMapboxDraw = ({ mapStyle, mapProvider, events, eventBus, snap
|
|
|
116
209
|
touchClickWorkaround.remove()
|
|
117
210
|
// Remove event listeners
|
|
118
211
|
eventBus.off(events.MAP_SET_STYLE, handleSetMapStyle)
|
|
212
|
+
eventBus.off(events.MAP_STYLE_CHANGE, handleStyleChanged)
|
|
119
213
|
eventBus.off(events.MAP_SET_SIZE, handleSetMapSize)
|
|
214
|
+
eventBus.off(events.MAP_SET_PIXEL_RATIO, handleSetPixelRatio)
|
|
120
215
|
// Disable draw mode but keep control on map for reuse
|
|
121
216
|
draw.changeMode('disabled')
|
|
122
217
|
// Clear adapter reference (but not _mapboxDrawInstance so it persists)
|