@defra/interactive-map 0.0.40-alpha → 0.0.42-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/button-definition.md +7 -8
- package/docs/api/control-definition.md +17 -1
- package/docs/api/panel-definition.md +5 -0
- package/docs/api/slots.md +50 -6
- package/docs/assets/images/slot-map.svg +61 -262
- package/docs/examples/add-polygons.mdx +8 -2
- package/docs/examples/add-symbols.mdx +8 -2
- package/docs/examples/draw-tools.mdx +3 -3
- package/docs/plugins/datasets.md +23 -15
- package/docs/plugins/draw.md +79 -16
- package/docs/plugins/map-key.md +147 -0
- package/docs/plugins/search.md +1 -1
- package/docs/plugins.md +5 -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/beta/use-location/dist/esm/im-use-location-plugin.js +1 -1
- package/plugins/beta/use-location/dist/umd/im-use-location-plugin.js +1 -1
- package/plugins/beta/use-location/src/manifest.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/createNewShape.js +41 -0
- package/plugins/draw/src/api/createNewShape.test.js +63 -0
- package/plugins/draw/src/api/editFeature.js +7 -4
- package/plugins/draw/src/api/editFeature.test.js +16 -0
- package/plugins/draw/src/api/newLine.js +2 -40
- package/plugins/draw/src/api/newPoint.js +42 -0
- package/plugins/draw/src/api/newPoint.test.js +117 -0
- package/plugins/draw/src/api/newPolygon.js +2 -40
- 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/manifest.js +1 -1
- 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 +68 -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 +43 -0
- package/plugins/{datasets → map-key}/src/components/Key/Key.module.scss +21 -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 +26 -0
- package/plugins/map-key/src/components/Key/KeyItem.test.jsx +67 -0
- package/plugins/map-key/src/components/Key/KeySvg.jsx +41 -0
- package/plugins/{datasets → map-key}/src/components/Key/KeySvg.test.jsx +14 -12
- package/plugins/map-key/src/components/Key/KeySvgLine.jsx +22 -0
- package/plugins/{datasets → map-key}/src/components/Key/KeySvgLine.test.jsx +1 -1
- package/plugins/{datasets → map-key}/src/components/Key/KeySvgPattern.jsx +7 -2
- package/plugins/{datasets → map-key}/src/components/Key/KeySvgPattern.test.jsx +8 -2
- package/plugins/map-key/src/components/Key/KeySvgRect.jsx +26 -0
- package/plugins/{datasets → map-key}/src/components/Key/KeySvgRect.test.jsx +1 -1
- package/plugins/{datasets → map-key}/src/components/Key/KeySvgSymbol.jsx +8 -3
- package/plugins/{datasets → map-key}/src/components/Key/KeySvgSymbol.test.jsx +17 -6
- package/plugins/map-key/src/components/Key/MapKey.jsx +53 -0
- package/plugins/map-key/src/components/Key/MapKey.test.jsx +147 -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/KeyboardHelp/KeyboardHelp.jsx +25 -23
- package/src/App/components/KeyboardHelp/KeyboardHelp.test.jsx +22 -5
- package/src/App/components/MoveControls/MoveControls.module.scss +41 -10
- package/src/App/components/Panel/Panel.jsx +65 -8
- package/src/App/components/Panel/Panel.module.scss +49 -15
- package/src/App/components/Panel/Panel.test.jsx +114 -1
- package/src/App/components/Tabs/Tabs.jsx +43 -17
- package/src/App/components/Tabs/Tabs.module.scss +32 -5
- package/src/App/components/Tabs/Tabs.test.jsx +40 -10
- 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/groupByKey.js +28 -0
- package/src/App/renderer/groupByKey.test.js +39 -0
- package/src/App/renderer/groupIntoTabs.js +42 -0
- package/src/App/renderer/groupIntoTabs.test.js +95 -0
- package/src/App/renderer/mapButtons.js +97 -129
- package/src/App/renderer/mapButtons.test.js +67 -83
- package/src/App/renderer/mapControls.js +4 -1
- package/src/App/renderer/mapControls.test.js +32 -0
- package/src/App/renderer/mapPanels.js +53 -11
- package/src/App/renderer/mapPanels.test.js +95 -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/appConfig.js +2 -2
- 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 +31 -3
- 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/KeySvgRect.jsx +0 -22
- 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,43 +1,43 @@
|
|
|
1
1
|
import { render, screen, act } from '@testing-library/react'
|
|
2
2
|
import { isVisibleWhen } from '../../registry/isVisibleWhen.js'
|
|
3
|
-
import {
|
|
3
|
+
import { MenuRadio } from './MenuRadio.jsx'
|
|
4
4
|
|
|
5
5
|
jest.mock('../../registry/isVisibleWhen.js', () => ({
|
|
6
6
|
isVisibleWhen: jest.fn()
|
|
7
7
|
}))
|
|
8
8
|
|
|
9
9
|
const onChange = jest.fn()
|
|
10
|
-
const baseItem = { id: '
|
|
10
|
+
const baseItem = { id: 'option-1', label: 'Option One' }
|
|
11
11
|
|
|
12
12
|
beforeEach(() => {
|
|
13
13
|
isVisibleWhen.mockReturnValue(true)
|
|
14
14
|
onChange.mockReset()
|
|
15
15
|
})
|
|
16
16
|
|
|
17
|
-
describe('
|
|
17
|
+
describe('MenuRadio', () => {
|
|
18
18
|
describe('visibility', () => {
|
|
19
19
|
it('renders when visibleWhen is not set', () => {
|
|
20
20
|
const { container } = render(
|
|
21
|
-
<
|
|
21
|
+
<MenuRadio menuGroupItem={baseItem} name='group' checked={false} onChange={onChange} />
|
|
22
22
|
)
|
|
23
23
|
expect(container.querySelector('input[type="radio"]')).toBeTruthy()
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
it('does not call isVisibleWhen when visibleWhen is not set', () => {
|
|
27
|
-
render(<
|
|
27
|
+
render(<MenuRadio menuGroupItem={baseItem} name='group' checked={false} onChange={onChange} />)
|
|
28
28
|
expect(isVisibleWhen).not.toHaveBeenCalled()
|
|
29
29
|
})
|
|
30
30
|
|
|
31
31
|
it('calls isVisibleWhen with the visibleWhen value', () => {
|
|
32
32
|
const visibleWhen = { menu: ['someValue'] }
|
|
33
|
-
render(<
|
|
33
|
+
render(<MenuRadio menuGroupItem={{ ...baseItem, visibleWhen }} name='group' checked={false} onChange={onChange} />)
|
|
34
34
|
expect(isVisibleWhen).toHaveBeenCalledWith(visibleWhen)
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
it('returns null when isVisibleWhen resolves to false', () => {
|
|
38
38
|
isVisibleWhen.mockReturnValue(false)
|
|
39
39
|
const { container } = render(
|
|
40
|
-
<
|
|
40
|
+
<MenuRadio menuGroupItem={{ ...baseItem, visibleWhen: {} }} name='group' checked={false} onChange={onChange} />
|
|
41
41
|
)
|
|
42
42
|
expect(container.firstChild).toBeNull()
|
|
43
43
|
})
|
|
@@ -45,7 +45,7 @@ describe('LayersMenuRadio', () => {
|
|
|
45
45
|
it('renders when isVisibleWhen resolves to true', () => {
|
|
46
46
|
isVisibleWhen.mockReturnValue(true)
|
|
47
47
|
const { container } = render(
|
|
48
|
-
<
|
|
48
|
+
<MenuRadio menuGroupItem={{ ...baseItem, visibleWhen: {} }} name='group' checked={false} onChange={onChange} />
|
|
49
49
|
)
|
|
50
50
|
expect(container.querySelector('input[type="radio"]')).toBeTruthy()
|
|
51
51
|
})
|
|
@@ -53,52 +53,52 @@ describe('LayersMenuRadio', () => {
|
|
|
53
53
|
|
|
54
54
|
describe('rendered output', () => {
|
|
55
55
|
it('renders the item label text', () => {
|
|
56
|
-
render(<
|
|
56
|
+
render(<MenuRadio menuGroupItem={baseItem} name='group' checked={false} onChange={onChange} />)
|
|
57
57
|
expect(screen.getByText('Option One')).toBeTruthy()
|
|
58
58
|
})
|
|
59
59
|
|
|
60
60
|
it('sets the name attribute on the input', () => {
|
|
61
61
|
const { container } = render(
|
|
62
|
-
<
|
|
62
|
+
<MenuRadio menuGroupItem={baseItem} name='my-radio-group' checked={false} onChange={onChange} />
|
|
63
63
|
)
|
|
64
64
|
expect(container.querySelector('input').name).toBe('my-radio-group')
|
|
65
65
|
})
|
|
66
66
|
|
|
67
67
|
it('sets checked to true when checked prop is true', () => {
|
|
68
68
|
const { container } = render(
|
|
69
|
-
<
|
|
69
|
+
<MenuRadio menuGroupItem={baseItem} name='group' checked onChange={onChange} />
|
|
70
70
|
)
|
|
71
71
|
expect(container.querySelector('input').checked).toBe(true)
|
|
72
72
|
})
|
|
73
73
|
|
|
74
74
|
it('sets checked to false when checked prop is false', () => {
|
|
75
75
|
const { container } = render(
|
|
76
|
-
<
|
|
76
|
+
<MenuRadio menuGroupItem={baseItem} name='group' checked={false} onChange={onChange} />
|
|
77
77
|
)
|
|
78
78
|
expect(container.querySelector('input').checked).toBe(false)
|
|
79
79
|
})
|
|
80
80
|
|
|
81
81
|
it('sets the input value to the item id', () => {
|
|
82
82
|
const { container } = render(
|
|
83
|
-
<
|
|
83
|
+
<MenuRadio menuGroupItem={baseItem} name='group' checked={false} onChange={onChange} />
|
|
84
84
|
)
|
|
85
|
-
expect(container.querySelector('input').value).toBe('
|
|
85
|
+
expect(container.querySelector('input').value).toBe('option-1')
|
|
86
86
|
})
|
|
87
87
|
|
|
88
88
|
it('associates the label with the input via htmlFor', () => {
|
|
89
89
|
const { container } = render(
|
|
90
|
-
<
|
|
90
|
+
<MenuRadio menuGroupItem={baseItem} name='group' checked={false} onChange={onChange} />
|
|
91
91
|
)
|
|
92
|
-
expect(container.querySelector('label').htmlFor).toBe('radio-1')
|
|
92
|
+
expect(container.querySelector('label').htmlFor).toBe('map-menu-radio-option-1')
|
|
93
93
|
})
|
|
94
94
|
|
|
95
95
|
it('calls onChange when the radio input changes', () => {
|
|
96
96
|
const { container } = render(
|
|
97
|
-
<
|
|
97
|
+
<MenuRadio menuGroupItem={baseItem} name='group' checked={false} onChange={onChange} />
|
|
98
98
|
)
|
|
99
99
|
const input = container.querySelector('input')
|
|
100
100
|
const propsKey = Object.keys(input).find(k => k.startsWith('__reactProps'))
|
|
101
|
-
act(() => { input[propsKey].onChange({ target: { value: '
|
|
101
|
+
act(() => { input[propsKey].onChange({ target: { value: 'option-1' } }) })
|
|
102
102
|
expect(onChange).toHaveBeenCalledTimes(1)
|
|
103
103
|
})
|
|
104
104
|
})
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { isVisibleWhen } from '../../registry/isVisibleWhen.js'
|
|
3
|
+
import { MenuRadio } from './MenuRadio.jsx'
|
|
4
|
+
import { GroupLegend } from './GroupLegend.jsx'
|
|
5
|
+
export const RadioGroupWrapper = ({ menuState, dispatch, menuGroup }) => {
|
|
6
|
+
const { id, items, visibleWhen } = menuGroup
|
|
7
|
+
const visible = visibleWhen ? isVisibleWhen(visibleWhen) : true
|
|
8
|
+
if (!visible) {
|
|
9
|
+
return null
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const value = menuState[id]
|
|
13
|
+
const handleChange = (event) => {
|
|
14
|
+
dispatch({ type: 'UPDATE_MENU_STATE', payload: { [id]: event.target.value } })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<GroupLegend menuGroup={menuGroup}>
|
|
19
|
+
<div className='govuk-radios govuk-radios--small' data-module='govuk-radios'>
|
|
20
|
+
{items.map((menuGroupItem) =>
|
|
21
|
+
<MenuRadio
|
|
22
|
+
key={menuGroupItem.id}
|
|
23
|
+
menuGroupItem={menuGroupItem}
|
|
24
|
+
name={id}
|
|
25
|
+
checked={menuGroupItem.id === value}
|
|
26
|
+
onChange={handleChange}
|
|
27
|
+
/>
|
|
28
|
+
)}
|
|
29
|
+
</div>
|
|
30
|
+
</GroupLegend>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { render, screen, act } from '@testing-library/react'
|
|
2
2
|
import { isVisibleWhen } from '../../registry/isVisibleWhen.js'
|
|
3
|
-
import {
|
|
3
|
+
import { RadioGroupWrapper } from './RadioGroupWrapper.jsx'
|
|
4
4
|
|
|
5
5
|
jest.mock('../../registry/isVisibleWhen.js', () => ({
|
|
6
6
|
isVisibleWhen: jest.fn()
|
|
@@ -8,8 +8,8 @@ jest.mock('../../registry/isVisibleWhen.js', () => ({
|
|
|
8
8
|
|
|
9
9
|
let capturedOnChange = null
|
|
10
10
|
|
|
11
|
-
jest.mock('./
|
|
12
|
-
|
|
11
|
+
jest.mock('./MenuRadio.jsx', () => ({
|
|
12
|
+
MenuRadio: ({ menuGroupItem, checked, name, onChange }) => {
|
|
13
13
|
capturedOnChange = onChange
|
|
14
14
|
return (
|
|
15
15
|
<div
|
|
@@ -22,7 +22,7 @@ jest.mock('./LayersMenuRadio.jsx', () => ({
|
|
|
22
22
|
}
|
|
23
23
|
}))
|
|
24
24
|
|
|
25
|
-
const
|
|
25
|
+
const makeProps = (menuState = {}) => ({
|
|
26
26
|
menuState,
|
|
27
27
|
dispatch: jest.fn()
|
|
28
28
|
})
|
|
@@ -39,51 +39,51 @@ beforeEach(() => {
|
|
|
39
39
|
capturedOnChange = null
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
-
describe('
|
|
42
|
+
describe('RadioGroupWrapper', () => {
|
|
43
43
|
describe('visibility', () => {
|
|
44
44
|
it('returns null when isVisibleWhen resolves to false', () => {
|
|
45
45
|
isVisibleWhen.mockReturnValue(false)
|
|
46
46
|
const { container } = render(
|
|
47
|
-
<
|
|
47
|
+
<RadioGroupWrapper {...makeProps()} menuGroup={{ ...baseGroup, visibleWhen: {} }} />
|
|
48
48
|
)
|
|
49
49
|
expect(container.firstChild).toBeNull()
|
|
50
50
|
})
|
|
51
51
|
|
|
52
52
|
it('renders when visibleWhen is not set', () => {
|
|
53
53
|
const { container } = render(
|
|
54
|
-
<
|
|
54
|
+
<RadioGroupWrapper {...makeProps()} menuGroup={baseGroup} />
|
|
55
55
|
)
|
|
56
56
|
expect(container.querySelector('.govuk-form-group')).toBeTruthy()
|
|
57
57
|
})
|
|
58
58
|
|
|
59
59
|
it('does not call isVisibleWhen when visibleWhen is not set', () => {
|
|
60
|
-
render(<
|
|
60
|
+
render(<RadioGroupWrapper {...makeProps()} menuGroup={baseGroup} />)
|
|
61
61
|
expect(isVisibleWhen).not.toHaveBeenCalled()
|
|
62
62
|
})
|
|
63
63
|
|
|
64
64
|
it('calls isVisibleWhen with the visibleWhen value', () => {
|
|
65
65
|
const visibleWhen = { menu: ['someValue'] }
|
|
66
|
-
render(<
|
|
66
|
+
render(<RadioGroupWrapper {...makeProps()} menuGroup={{ ...baseGroup, visibleWhen }} />)
|
|
67
67
|
expect(isVisibleWhen).toHaveBeenCalledWith(visibleWhen)
|
|
68
68
|
})
|
|
69
69
|
})
|
|
70
70
|
|
|
71
71
|
describe('rendered output', () => {
|
|
72
72
|
it('renders the group label as the legend', () => {
|
|
73
|
-
render(<
|
|
73
|
+
render(<RadioGroupWrapper {...makeProps()} menuGroup={baseGroup} />)
|
|
74
74
|
expect(screen.getByText('My Group')).toBeTruthy()
|
|
75
75
|
})
|
|
76
76
|
|
|
77
|
-
it('renders a
|
|
77
|
+
it('renders a MenuRadio for each item', () => {
|
|
78
78
|
const { getAllByTestId } = render(
|
|
79
|
-
<
|
|
79
|
+
<RadioGroupWrapper {...makeProps()} menuGroup={baseGroup} />
|
|
80
80
|
)
|
|
81
81
|
expect(getAllByTestId('layers-menu-radio')).toHaveLength(2)
|
|
82
82
|
})
|
|
83
83
|
|
|
84
84
|
it('passes the group id as the name to each radio item', () => {
|
|
85
85
|
const { getAllByTestId } = render(
|
|
86
|
-
<
|
|
86
|
+
<RadioGroupWrapper {...makeProps()} menuGroup={baseGroup} />
|
|
87
87
|
)
|
|
88
88
|
getAllByTestId('layers-menu-radio').forEach(radio => {
|
|
89
89
|
expect(radio.dataset.name).toBe('group-1')
|
|
@@ -94,7 +94,7 @@ describe('LayersRadioGroupWrapper', () => {
|
|
|
94
94
|
describe('checked state', () => {
|
|
95
95
|
it('marks the item matching menuState as checked', () => {
|
|
96
96
|
const { getAllByTestId } = render(
|
|
97
|
-
<
|
|
97
|
+
<RadioGroupWrapper {...makeProps({ 'group-1': 'opt-a' })} menuGroup={baseGroup} />
|
|
98
98
|
)
|
|
99
99
|
const radios = getAllByTestId('layers-menu-radio')
|
|
100
100
|
expect(radios[0].dataset.checked).toBe('true')
|
|
@@ -103,7 +103,7 @@ describe('LayersRadioGroupWrapper', () => {
|
|
|
103
103
|
|
|
104
104
|
it('marks no item as checked when menuState has no value for the group', () => {
|
|
105
105
|
const { getAllByTestId } = render(
|
|
106
|
-
<
|
|
106
|
+
<RadioGroupWrapper {...makeProps({})} menuGroup={baseGroup} />
|
|
107
107
|
)
|
|
108
108
|
getAllByTestId('layers-menu-radio').forEach(radio => {
|
|
109
109
|
expect(radio.dataset.checked).toBe('false')
|
|
@@ -113,10 +113,10 @@ describe('LayersRadioGroupWrapper', () => {
|
|
|
113
113
|
|
|
114
114
|
describe('handleChange', () => {
|
|
115
115
|
it('dispatches UPDATE_MENU_STATE with the selected item id', () => {
|
|
116
|
-
const
|
|
117
|
-
render(<
|
|
116
|
+
const props = makeProps({ 'group-1': 'opt-a' })
|
|
117
|
+
render(<RadioGroupWrapper {...props} menuGroup={baseGroup} />)
|
|
118
118
|
act(() => { capturedOnChange({ target: { value: 'opt-b' } }) })
|
|
119
|
-
expect(
|
|
119
|
+
expect(props.dispatch).toHaveBeenCalledWith({
|
|
120
120
|
type: 'UPDATE_MENU_STATE',
|
|
121
121
|
payload: { 'group-1': 'opt-b' }
|
|
122
122
|
})
|
|
@@ -124,10 +124,10 @@ describe('LayersRadioGroupWrapper', () => {
|
|
|
124
124
|
|
|
125
125
|
it('dispatches using the group id as the payload key', () => {
|
|
126
126
|
const group = { ...baseGroup, id: 'another-group' }
|
|
127
|
-
const
|
|
128
|
-
render(<
|
|
127
|
+
const props = makeProps({ 'another-group': 'opt-a' })
|
|
128
|
+
render(<RadioGroupWrapper {...props} menuGroup={group} />)
|
|
129
129
|
act(() => { capturedOnChange({ target: { value: 'opt-b' } }) })
|
|
130
|
-
expect(
|
|
130
|
+
expect(props.dispatch).toHaveBeenCalledWith({
|
|
131
131
|
type: 'UPDATE_MENU_STATE',
|
|
132
132
|
payload: { 'another-group': 'opt-b' }
|
|
133
133
|
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import './menu.scss'
|
|
2
|
+
|
|
3
|
+
export default function createPlugin (options = {}) {
|
|
4
|
+
return {
|
|
5
|
+
noKeyItemText: 'No features displayed',
|
|
6
|
+
...options,
|
|
7
|
+
id: 'menu',
|
|
8
|
+
load: async () => {
|
|
9
|
+
const module = (await import(/* webpackChunkName: "im-menu-plugin" */ './manifest.js')).manifest
|
|
10
|
+
return module
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import createPlugin from './index.js'
|
|
2
|
+
|
|
3
|
+
jest.mock('./menu.scss', () => {})
|
|
4
|
+
jest.mock('./manifest.js', () => ({ manifest: { InitComponent: 'MenuInit', panels: [] } }))
|
|
5
|
+
|
|
6
|
+
describe('createPlugin', () => {
|
|
7
|
+
it('returns the menu id', () => {
|
|
8
|
+
expect(createPlugin().id).toBe('menu')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('id cannot be overridden by options', () => {
|
|
12
|
+
expect(createPlugin({ id: 'other' }).id).toBe('menu')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('returns the default noKeyItemText', () => {
|
|
16
|
+
expect(createPlugin().noKeyItemText).toBe('No features displayed')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('allows noKeyItemText to be overridden', () => {
|
|
20
|
+
expect(createPlugin({ noKeyItemText: 'Nothing here' }).noKeyItemText).toBe('Nothing here')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('merges additional options into the returned object', () => {
|
|
24
|
+
expect(createPlugin({ custom: true }).custom).toBe(true)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('load() resolves to the manifest', async () => {
|
|
28
|
+
const result = await createPlugin().load()
|
|
29
|
+
expect(result).toEqual({ InitComponent: 'MenuInit', panels: [] })
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
import { createMenu } from './createMenu.js'
|
|
3
|
+
import { attachPluginStateRef } from '../registry/isVisibleWhen.js'
|
|
4
|
+
|
|
5
|
+
// additional possible params here are: appState, mapProvider,
|
|
6
|
+
export function MenuInit ({ pluginConfig, pluginState, mapState, services }) {
|
|
7
|
+
const { dispatch } = pluginState
|
|
8
|
+
const { eventBus } = services
|
|
9
|
+
|
|
10
|
+
const pluginStateRef = useRef(pluginState)
|
|
11
|
+
pluginStateRef.current = pluginState
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (!mapState.isMapReady) {
|
|
15
|
+
return () => {}
|
|
16
|
+
}
|
|
17
|
+
attachPluginStateRef(pluginStateRef)
|
|
18
|
+
const { menu } = pluginConfig
|
|
19
|
+
return createMenu({ menu, eventBus, dispatch, pluginStateRef })
|
|
20
|
+
}, [mapState.isMapReady])
|
|
21
|
+
|
|
22
|
+
// Notify any plugins, that are listening, to the menu's state change
|
|
23
|
+
useEffect(() => eventBus.emit('menu:changed', pluginState.menuState), [pluginState.menuState])
|
|
24
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { render } from '@testing-library/react'
|
|
2
|
+
import { MenuInit } from './MenuInit.jsx'
|
|
3
|
+
import { createMenu } from './createMenu.js'
|
|
4
|
+
|
|
5
|
+
jest.mock('./createMenu.js', () => ({
|
|
6
|
+
createMenu: jest.fn()
|
|
7
|
+
}))
|
|
8
|
+
|
|
9
|
+
const mockRemove = jest.fn()
|
|
10
|
+
const mockDispatch = jest.fn()
|
|
11
|
+
const eventBus = { on: jest.fn(), off: jest.fn(), emit: jest.fn(), emitWhenRequested: jest.fn() }
|
|
12
|
+
const services = { eventBus }
|
|
13
|
+
const pluginState = { dispatch: mockDispatch, menuState: null }
|
|
14
|
+
const pluginConfig = { menu: [] }
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
jest.clearAllMocks()
|
|
18
|
+
createMenu.mockReturnValue(mockRemove)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
describe('MenuInit', () => {
|
|
22
|
+
it('does not call createMenu when map is not ready', () => {
|
|
23
|
+
render(<MenuInit mapState={{ isMapReady: false }} services={services} pluginState={pluginState} pluginConfig={pluginConfig} />)
|
|
24
|
+
expect(createMenu).not.toHaveBeenCalled()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('calls createMenu with eventBus when map is ready', () => {
|
|
28
|
+
render(<MenuInit mapState={{ isMapReady: true }} services={services} pluginState={pluginState} pluginConfig={pluginConfig} />)
|
|
29
|
+
expect(createMenu).toHaveBeenCalledWith(expect.objectContaining({ eventBus }))
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('calls remove on unmount when map was ready', () => {
|
|
33
|
+
const { unmount } = render(<MenuInit mapState={{ isMapReady: true }} services={services} pluginState={pluginState} pluginConfig={pluginConfig} />)
|
|
34
|
+
unmount()
|
|
35
|
+
expect(mockRemove).toHaveBeenCalled()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('does not call remove on unmount when map was not ready', () => {
|
|
39
|
+
const { unmount } = render(<MenuInit mapState={{ isMapReady: false }} services={services} pluginState={pluginState} pluginConfig={pluginConfig} />)
|
|
40
|
+
unmount()
|
|
41
|
+
expect(mockRemove).not.toHaveBeenCalled()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('calls createMenu again when isMapReady changes to true', () => {
|
|
45
|
+
const { rerender } = render(<MenuInit mapState={{ isMapReady: false }} services={services} pluginState={pluginState} pluginConfig={pluginConfig} />)
|
|
46
|
+
expect(createMenu).not.toHaveBeenCalled()
|
|
47
|
+
rerender(<MenuInit mapState={{ isMapReady: true }} services={services} pluginState={pluginState} pluginConfig={pluginConfig} />)
|
|
48
|
+
expect(createMenu).toHaveBeenCalledTimes(1)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { setDatasetRegistry } from '../registry/getDatasetRegistry.js'
|
|
2
|
+
|
|
3
|
+
export const createMenu = ({ menu, eventBus, dispatch, pluginStateRef }) => {
|
|
4
|
+
dispatch({ type: 'SET_MENU', payload: { menu } })
|
|
5
|
+
// Request a handle on the datasetsRegistry singleton, so that the menu plugin can access it when needed
|
|
6
|
+
eventBus.requestOnce('datasets:registry', setDatasetRegistry)
|
|
7
|
+
// add a listener for the menu:state event, which will be emitted whenever requested by other plugins,
|
|
8
|
+
// e.g. the datasets plugin, so they can access the menu state.
|
|
9
|
+
return eventBus.emitWhenRequested('menu:state', pluginStateRef)
|
|
10
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createMenu } from './createMenu.js'
|
|
2
|
+
import { setDatasetRegistry } from '../registry/getDatasetRegistry.js'
|
|
3
|
+
|
|
4
|
+
jest.mock('../registry/getDatasetRegistry.js', () => ({
|
|
5
|
+
setDatasetRegistry: jest.fn()
|
|
6
|
+
}))
|
|
7
|
+
|
|
8
|
+
const makeEventBus = () => ({
|
|
9
|
+
on: jest.fn(),
|
|
10
|
+
off: jest.fn(),
|
|
11
|
+
emit: jest.fn(),
|
|
12
|
+
requestOnce: jest.fn(),
|
|
13
|
+
emitWhenRequested: jest.fn()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
describe('createMenu', () => {
|
|
17
|
+
it('dispatches SET_MENU with the menu', () => {
|
|
18
|
+
const eventBus = makeEventBus()
|
|
19
|
+
const dispatch = jest.fn()
|
|
20
|
+
const menu = [{ id: 'layer1' }]
|
|
21
|
+
createMenu({ menu, eventBus, dispatch, pluginStateRef: {} })
|
|
22
|
+
expect(dispatch).toHaveBeenCalledWith({ type: 'SET_MENU', payload: { menu } })
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('calls requestOnce for the datasets registry', () => {
|
|
26
|
+
const eventBus = makeEventBus()
|
|
27
|
+
createMenu({ eventBus, dispatch: jest.fn(), pluginStateRef: {} })
|
|
28
|
+
expect(eventBus.requestOnce).toHaveBeenCalledWith('datasets:registry', setDatasetRegistry)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('calls emitWhenRequested for menu:state', () => {
|
|
32
|
+
const eventBus = makeEventBus()
|
|
33
|
+
const pluginStateRef = { current: {} }
|
|
34
|
+
createMenu({ eventBus, dispatch: jest.fn(), pluginStateRef })
|
|
35
|
+
expect(eventBus.emitWhenRequested).toHaveBeenCalledWith('menu:state', pluginStateRef)
|
|
36
|
+
})
|
|
37
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Menu } from './components/Menu/Menu.jsx'
|
|
2
|
+
import './registry/getDatasetRegistry.js'
|
|
3
|
+
import { MenuInit } from './initialise/MenuInit.jsx'
|
|
4
|
+
import { initialState, actions } from './reducers/pluginState.js'
|
|
5
|
+
|
|
6
|
+
export const manifest = {
|
|
7
|
+
InitComponent: MenuInit,
|
|
8
|
+
reducer: {
|
|
9
|
+
initialState,
|
|
10
|
+
actions
|
|
11
|
+
},
|
|
12
|
+
panels: [
|
|
13
|
+
{
|
|
14
|
+
id: 'menu',
|
|
15
|
+
label: 'Layers',
|
|
16
|
+
mobile: { slot: 'drawer', modal: true, dismissible: true },
|
|
17
|
+
tablet: { slot: 'left-top', dismissible: true, exclusive: true, width: '260px' },
|
|
18
|
+
desktop: { slot: 'left-top', modal: false, dismissible: true, exclusive: true, width: '280px' },
|
|
19
|
+
render: Menu
|
|
20
|
+
}],
|
|
21
|
+
buttons: [{
|
|
22
|
+
id: 'menuButton',
|
|
23
|
+
label: 'Layers',
|
|
24
|
+
panelId: 'menu',
|
|
25
|
+
iconId: 'layersMenu',
|
|
26
|
+
mobile: { slot: 'top-left', showLabel: true },
|
|
27
|
+
tablet: { slot: 'top-left', showLabel: true },
|
|
28
|
+
desktop: { slot: 'top-left', showLabel: true }
|
|
29
|
+
}],
|
|
30
|
+
|
|
31
|
+
icons: [{
|
|
32
|
+
id: 'layersMenu',
|
|
33
|
+
svgContent: '<path d="M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z"></path><path d="M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12"></path><path d="M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17"></path>'
|
|
34
|
+
}]
|
|
35
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { manifest } from './manifest.js'
|
|
2
|
+
import { Menu } from './components/Menu/Menu.jsx'
|
|
3
|
+
import { MenuInit } from './initialise/MenuInit.jsx'
|
|
4
|
+
|
|
5
|
+
jest.mock('./components/Menu/Menu.jsx', () => ({ Menu: jest.fn() }))
|
|
6
|
+
jest.mock('./initialise/MenuInit.jsx', () => ({ MenuInit: jest.fn() }))
|
|
7
|
+
jest.mock('./registry/getDatasetRegistry.js', () => ({}))
|
|
8
|
+
|
|
9
|
+
describe('manifest', () => {
|
|
10
|
+
it('sets InitComponent to MenuInit', () => {
|
|
11
|
+
expect(manifest.InitComponent).toBe(MenuInit)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
describe('panels', () => {
|
|
15
|
+
it('defines one panel', () => {
|
|
16
|
+
expect(manifest.panels).toHaveLength(1)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('panel has id menu', () => {
|
|
20
|
+
expect(manifest.panels[0].id).toBe('menu')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('panel render is Menu', () => {
|
|
24
|
+
expect(manifest.panels[0].render).toBe(Menu)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('panel defines mobile, tablet and desktop slots', () => {
|
|
28
|
+
const { mobile, tablet, desktop } = manifest.panels[0]
|
|
29
|
+
expect(mobile.slot).toBe('drawer')
|
|
30
|
+
expect(tablet.slot).toBe('left-top')
|
|
31
|
+
expect(desktop.slot).toBe('left-top')
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
describe('buttons', () => {
|
|
36
|
+
it('defines one button', () => {
|
|
37
|
+
expect(manifest.buttons).toHaveLength(1)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('button has id menuButton and links to the menu panel', () => {
|
|
41
|
+
expect(manifest.buttons[0].id).toBe('menuButton')
|
|
42
|
+
expect(manifest.buttons[0].panelId).toBe('menu')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('button references the layersMenu icon', () => {
|
|
46
|
+
expect(manifest.buttons[0].iconId).toBe('layersMenu')
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('icons', () => {
|
|
51
|
+
it('defines one icon', () => {
|
|
52
|
+
expect(manifest.icons).toHaveLength(1)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('icon id is layersMenu', () => {
|
|
56
|
+
expect(manifest.icons[0].id).toBe('layersMenu')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('icon has svgContent', () => {
|
|
60
|
+
expect(manifest.icons[0].svgContent).toBeTruthy()
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { buildMenuState } from './menuStateReducer.js'
|
|
2
|
+
|
|
3
|
+
describe('buildMenuState', () => {
|
|
4
|
+
it('returns an empty object for an empty menu', () => {
|
|
5
|
+
expect(buildMenuState([])).toEqual({})
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
it('ignores non-radio menu groups', () => {
|
|
9
|
+
const menu = [{ id: 'layer', type: 'checkbox', value: 'a' }]
|
|
10
|
+
expect(buildMenuState(menu)).toEqual({})
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('uses the explicit value when set', () => {
|
|
14
|
+
const menu = [{ id: 'datasets', type: 'radio', value: 'floodZones', items: [{ value: 'other' }] }]
|
|
15
|
+
expect(buildMenuState(menu)).toEqual({ datasets: 'floodZones' })
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('falls back to the first item value when no value is set', () => {
|
|
19
|
+
const menu = [{ id: 'datasets', type: 'radio', items: [{ value: 'floodZones' }, { value: 'other' }] }]
|
|
20
|
+
expect(buildMenuState(menu)).toEqual({ datasets: 'floodZones' })
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('handles multiple radio groups', () => {
|
|
24
|
+
const menu = [
|
|
25
|
+
{ id: 'datasets', type: 'radio', value: 'floodZones' },
|
|
26
|
+
{ id: 'timeframe', type: 'radio', items: [{ value: 'presentDay' }] }
|
|
27
|
+
]
|
|
28
|
+
expect(buildMenuState(menu)).toEqual({ datasets: 'floodZones', timeframe: 'presentDay' })
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('mixes radio and non-radio groups, only including radios', () => {
|
|
32
|
+
const menu = [
|
|
33
|
+
{ id: 'layer', type: 'checkbox', value: 'a' },
|
|
34
|
+
{ id: 'datasets', type: 'radio', value: 'floodZones' }
|
|
35
|
+
]
|
|
36
|
+
expect(buildMenuState(menu)).toEqual({ datasets: 'floodZones' })
|
|
37
|
+
})
|
|
38
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { buildMenuState } from './menuStateReducer.js'
|
|
2
|
+
|
|
3
|
+
const initialState = {
|
|
4
|
+
actionsArray: [],
|
|
5
|
+
menu: [],
|
|
6
|
+
menuState: {}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const updateMenuState = (state, payload) => {
|
|
10
|
+
return {
|
|
11
|
+
...state,
|
|
12
|
+
menuState: { ...state.menuState, ...payload }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const setMenu = (state, payload) => {
|
|
17
|
+
const { menu } = payload
|
|
18
|
+
// build the initial menuState for radios from the menu
|
|
19
|
+
const menuState = buildMenuState(menu)
|
|
20
|
+
return {
|
|
21
|
+
...state,
|
|
22
|
+
menu,
|
|
23
|
+
menuState
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const actions = {
|
|
28
|
+
SET_MENU: setMenu,
|
|
29
|
+
UPDATE_MENU_STATE: updateMenuState
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
initialState,
|
|
34
|
+
actions
|
|
35
|
+
}
|