@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
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { render } from '@testing-library/react'
|
|
2
|
+
import { Menu } from './Menu.jsx'
|
|
3
|
+
|
|
4
|
+
let capturedOnChange = null
|
|
5
|
+
|
|
6
|
+
jest.mock('./MenuCheckbox.jsx', () => ({
|
|
7
|
+
MenuCheckbox: ({ menuGroupItem, onChange }) => {
|
|
8
|
+
capturedOnChange = onChange
|
|
9
|
+
return (
|
|
10
|
+
<div
|
|
11
|
+
data-testid='layers-menu-checkbox'
|
|
12
|
+
data-item-id={menuGroupItem.id}
|
|
13
|
+
/>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
}))
|
|
17
|
+
|
|
18
|
+
jest.mock('./RadioGroupWrapper.jsx', () => ({
|
|
19
|
+
RadioGroupWrapper: ({ menuGroup }) => (
|
|
20
|
+
<div data-testid='layers-radio-group-wrapper' data-group-id={menuGroup.id} />
|
|
21
|
+
)
|
|
22
|
+
}))
|
|
23
|
+
|
|
24
|
+
jest.mock('./GroupLegend.jsx', () => ({
|
|
25
|
+
GroupLegend: ({ menuGroup, children }) => (
|
|
26
|
+
<div data-testid='layers-menu-group-wrapper' data-group-id={menuGroup.id}>
|
|
27
|
+
{children}
|
|
28
|
+
</div>
|
|
29
|
+
)
|
|
30
|
+
}))
|
|
31
|
+
|
|
32
|
+
const makePluginState = (menu = [], extra = {}) => ({
|
|
33
|
+
menu,
|
|
34
|
+
menuState: {},
|
|
35
|
+
dispatch: jest.fn(),
|
|
36
|
+
...extra
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const appConfig = {
|
|
40
|
+
id: 'map'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe('Menu', () => {
|
|
44
|
+
describe('container class', () => {
|
|
45
|
+
it('renders the base container class when no groups have a groupLabel', () => {
|
|
46
|
+
const pluginState = makePluginState([{ id: 'g1', type: 'checkbox', items: [] }])
|
|
47
|
+
const { container } = render(<Menu pluginState={pluginState} appConfig={appConfig} />)
|
|
48
|
+
const div = container.firstChild
|
|
49
|
+
expect(div.className).toBe('im-c-menu')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('adds the --has-groups modifier when at least one group has a groupLabel', () => {
|
|
53
|
+
const pluginState = makePluginState([{ id: 'g1', type: 'checkbox', groupLabel: 'My Group', items: [] }])
|
|
54
|
+
const { container } = render(<Menu pluginState={pluginState} />)
|
|
55
|
+
const div = container.firstChild
|
|
56
|
+
expect(div.className).toBe('im-c-menu im-c-menu--has-groups')
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
describe('empty menu', () => {
|
|
61
|
+
it('renders the container with no children when menu is empty', () => {
|
|
62
|
+
const pluginState = makePluginState([])
|
|
63
|
+
const { container } = render(<Menu pluginState={pluginState} />)
|
|
64
|
+
expect(container.firstChild.children).toHaveLength(0)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('uses an empty array when menu is not provided', () => {
|
|
68
|
+
const { container } = render(<Menu pluginState={{}} />)
|
|
69
|
+
expect(container.firstChild.children).toHaveLength(0)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
describe('checkbox groups', () => {
|
|
74
|
+
it('renders a GroupLegend for each checkbox group', () => {
|
|
75
|
+
const pluginState = makePluginState([
|
|
76
|
+
{ id: 'g1', type: 'checkbox', items: [] },
|
|
77
|
+
{ id: 'g2', type: 'checkbox', items: [] }
|
|
78
|
+
])
|
|
79
|
+
const { getAllByTestId } = render(<Menu pluginState={pluginState} />)
|
|
80
|
+
expect(getAllByTestId('layers-menu-group-wrapper')).toHaveLength(2)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('renders a MenuCheckbox for each item in a checkbox group', () => {
|
|
84
|
+
const pluginState = makePluginState([
|
|
85
|
+
{ id: 'g1', type: 'checkbox', items: [{ id: 'item-a' }, { id: 'item-b' }] }
|
|
86
|
+
])
|
|
87
|
+
const { getAllByTestId } = render(<Menu pluginState={pluginState} />)
|
|
88
|
+
expect(getAllByTestId('layers-menu-checkbox')).toHaveLength(2)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('passes the correct group to GroupLegend', () => {
|
|
92
|
+
const group = { id: 'group-x', type: 'checkbox', items: [] }
|
|
93
|
+
const pluginState = makePluginState([group])
|
|
94
|
+
const { getByTestId } = render(<Menu pluginState={pluginState} />)
|
|
95
|
+
expect(getByTestId('layers-menu-group-wrapper').dataset.groupId).toBe('group-x')
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('passes the correct item to MenuCheckbox', () => {
|
|
99
|
+
const pluginState = makePluginState([
|
|
100
|
+
{ id: 'g1', type: 'checkbox', items: [{ id: 'item-1' }] }
|
|
101
|
+
])
|
|
102
|
+
const { getByTestId } = render(<Menu pluginState={pluginState} />)
|
|
103
|
+
expect(getByTestId('layers-menu-checkbox').dataset.itemId).toBe('item-1')
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
describe('radio groups', () => {
|
|
108
|
+
it('renders a RadioGroupWrapper for non-checkbox groups', () => {
|
|
109
|
+
const pluginState = makePluginState([
|
|
110
|
+
{ id: 'r1', type: 'radio', items: [{ id: 'opt1' }, { id: 'opt2' }] }
|
|
111
|
+
])
|
|
112
|
+
const { getAllByTestId } = render(<Menu pluginState={pluginState} />)
|
|
113
|
+
expect(getAllByTestId('layers-radio-group-wrapper')).toHaveLength(1)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('passes the correct group to RadioGroupWrapper', () => {
|
|
117
|
+
const pluginState = makePluginState([
|
|
118
|
+
{ id: 'radio-group-1', type: 'radio', items: [] }
|
|
119
|
+
])
|
|
120
|
+
const { getByTestId } = render(<Menu pluginState={pluginState} />)
|
|
121
|
+
expect(getByTestId('layers-radio-group-wrapper').dataset.groupId).toBe('radio-group-1')
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('does not render a GroupLegend for radio groups', () => {
|
|
125
|
+
const pluginState = makePluginState([{ id: 'r1', type: 'radio', items: [] }])
|
|
126
|
+
const { queryByTestId } = render(<Menu pluginState={pluginState} />)
|
|
127
|
+
expect(queryByTestId('layers-menu-group-wrapper')).toBeNull()
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
describe('mixed groups', () => {
|
|
132
|
+
it('renders both checkbox and radio wrappers when both types are present', () => {
|
|
133
|
+
const pluginState = makePluginState([
|
|
134
|
+
{ id: 'c1', type: 'checkbox', items: [] },
|
|
135
|
+
{ id: 'r1', type: 'radio', items: [] }
|
|
136
|
+
])
|
|
137
|
+
const { getByTestId } = render(<Menu pluginState={pluginState} />)
|
|
138
|
+
expect(getByTestId('layers-menu-group-wrapper')).toBeTruthy()
|
|
139
|
+
expect(getByTestId('layers-radio-group-wrapper')).toBeTruthy()
|
|
140
|
+
})
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
describe('handleDatasetChange', () => {
|
|
144
|
+
it('passes handleOnChange from the config item as onChange', () => {
|
|
145
|
+
const handleOnChange = jest.fn()
|
|
146
|
+
const pluginState = makePluginState([
|
|
147
|
+
{ id: 'g1', type: 'checkbox', items: [{ id: 'dataset-abc', handleOnChange }] }
|
|
148
|
+
])
|
|
149
|
+
render(<Menu pluginState={pluginState} />)
|
|
150
|
+
expect(capturedOnChange).toBe(handleOnChange)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('onChange is undefined when the config item has no handleOnChange', () => {
|
|
154
|
+
const pluginState = makePluginState([
|
|
155
|
+
{ id: 'g1', type: 'checkbox', items: [{ id: 'dataset-abc' }] }
|
|
156
|
+
])
|
|
157
|
+
render(<Menu pluginState={pluginState} />)
|
|
158
|
+
expect(capturedOnChange).toBeUndefined()
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useIdPrefix } from './useIdPrefix.jsx'
|
|
2
|
+
|
|
3
|
+
export const MenuCheckbox = ({ dispatch, menuGroupItem, onChange, checked }) => {
|
|
4
|
+
const itemClass = `im-c-menu__item govuk-checkboxes govuk-checkboxes--small${checked ? '' : ' im-c-menu__item--checked'}`
|
|
5
|
+
const itemId = useIdPrefix(`checkbox-${menuGroupItem.id}`)
|
|
6
|
+
|
|
7
|
+
const handleOnChange = event => {
|
|
8
|
+
const _checked = Boolean(event.target?.checked)
|
|
9
|
+
if (onChange) {
|
|
10
|
+
// The menu config can optionally pass handleOnChange, which is passed in as onChange
|
|
11
|
+
// and called here
|
|
12
|
+
onChange(_checked)
|
|
13
|
+
}
|
|
14
|
+
// Also update the menu state, so any visibleWhen implementations can also handle it
|
|
15
|
+
dispatch({ type: 'UPDATE_MENU_STATE', payload: { [menuGroupItem.id]: _checked } })
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div key={itemId} className={itemClass} data-module='govuk-checkboxes'>
|
|
20
|
+
<div className='govuk-checkboxes__item'>
|
|
21
|
+
<input
|
|
22
|
+
className='govuk-checkboxes__input'
|
|
23
|
+
id={itemId}
|
|
24
|
+
name={itemId}
|
|
25
|
+
type='checkbox'
|
|
26
|
+
checked={checked}
|
|
27
|
+
onChange={handleOnChange}
|
|
28
|
+
/>
|
|
29
|
+
<label className='im-c-menu__item-label govuk-label govuk-checkboxes__label' htmlFor={itemId}>
|
|
30
|
+
{menuGroupItem.label}
|
|
31
|
+
</label>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { render, screen, act } from '@testing-library/react'
|
|
2
|
+
import { MenuCheckbox } from './MenuCheckbox.jsx'
|
|
3
|
+
|
|
4
|
+
const onChange = jest.fn()
|
|
5
|
+
const dispatch = jest.fn()
|
|
6
|
+
const menuGroupItem = { id: 'dataset-1', label: 'Dataset One' }
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
onChange.mockReset()
|
|
10
|
+
dispatch.mockReset()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const renderCheckbox = (props = {}) =>
|
|
14
|
+
render(<MenuCheckbox menuGroupItem={menuGroupItem} onChange={onChange} dispatch={dispatch} checked {...props} />)
|
|
15
|
+
|
|
16
|
+
describe('MenuCheckbox', () => {
|
|
17
|
+
describe('rendered output', () => {
|
|
18
|
+
it('renders a checkbox input', () => {
|
|
19
|
+
const { container } = renderCheckbox()
|
|
20
|
+
expect(container.querySelector('input[type="checkbox"]')).toBeTruthy()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('renders the menuGroupItem label', () => {
|
|
24
|
+
renderCheckbox()
|
|
25
|
+
expect(screen.getByText('Dataset One')).toBeTruthy()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('associates the label with the input via htmlFor', () => {
|
|
29
|
+
const { container } = renderCheckbox()
|
|
30
|
+
const label = container.querySelector('label')
|
|
31
|
+
const input = container.querySelector('input')
|
|
32
|
+
expect(label.htmlFor).toBe(input.id)
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
describe('checked state', () => {
|
|
37
|
+
it('is checked when checked prop is true', () => {
|
|
38
|
+
const { container } = renderCheckbox({ checked: true })
|
|
39
|
+
expect(container.querySelector('input').checked).toBe(true)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('is unchecked when checked prop is false', () => {
|
|
43
|
+
const { container } = renderCheckbox({ checked: false })
|
|
44
|
+
expect(container.querySelector('input').checked).toBe(false)
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
describe('item class', () => {
|
|
49
|
+
it('does not include the --checked modifier when checked is true', () => {
|
|
50
|
+
const { container } = renderCheckbox({ checked: true })
|
|
51
|
+
expect(container.firstChild.className).not.toContain('im-c-menu__item--checked')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('includes the --checked modifier when checked is false', () => {
|
|
55
|
+
const { container } = renderCheckbox({ checked: false })
|
|
56
|
+
expect(container.firstChild.className).toContain('im-c-menu__item--checked')
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
describe('handleOnChange', () => {
|
|
61
|
+
const triggerChange = (container, checked) => {
|
|
62
|
+
const input = container.querySelector('input')
|
|
63
|
+
const propsKey = Object.keys(input).find(k => k.startsWith('__reactProps'))
|
|
64
|
+
act(() => { input[propsKey].onChange({ target: { checked, value: input.value } }) })
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
it('calls onChange with true when the checkbox is checked', () => {
|
|
68
|
+
const { container } = renderCheckbox()
|
|
69
|
+
triggerChange(container, true)
|
|
70
|
+
expect(onChange).toHaveBeenCalledWith(true)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('calls onChange with false when the checkbox is unchecked', () => {
|
|
74
|
+
const { container } = renderCheckbox()
|
|
75
|
+
triggerChange(container, false)
|
|
76
|
+
expect(onChange).toHaveBeenCalledWith(false)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('dispatches UPDATE_MENU_STATE with the item id and checked value', () => {
|
|
80
|
+
const { container } = renderCheckbox()
|
|
81
|
+
triggerChange(container, true)
|
|
82
|
+
expect(dispatch).toHaveBeenCalledWith({
|
|
83
|
+
type: 'UPDATE_MENU_STATE',
|
|
84
|
+
payload: { 'dataset-1': true }
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('does not throw when onChange is not provided', () => {
|
|
89
|
+
const { container } = renderCheckbox({ onChange: undefined })
|
|
90
|
+
expect(() => triggerChange(container, true)).not.toThrow()
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { RadioGroupWrapper } from './RadioGroupWrapper.jsx'
|
|
3
|
+
import { CheckboxGroupWrapper } from './CheckboxGroupWrapper.jsx'
|
|
4
|
+
|
|
5
|
+
export const MenuGroup = ({ menuGroup, dispatch, menuState }) => {
|
|
6
|
+
if (menuGroup.type === 'checkbox') {
|
|
7
|
+
return (<CheckboxGroupWrapper menuGroup={menuGroup} dispatch={dispatch} menuState={menuState} />)
|
|
8
|
+
} else {
|
|
9
|
+
return (<RadioGroupWrapper menuGroup={menuGroup} dispatch={dispatch} menuState={menuState} />)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { isVisibleWhen } from '../../registry/isVisibleWhen.js'
|
|
2
|
+
import { useIdPrefix } from './useIdPrefix.jsx'
|
|
2
3
|
|
|
3
|
-
export const
|
|
4
|
-
const itemClass = 'im-c-
|
|
4
|
+
export const MenuRadio = ({ menuGroupItem, name, checked, onChange }) => {
|
|
5
|
+
const itemClass = 'im-c-menu__item govuk-radios govuk-radios--small"'
|
|
6
|
+
const itemId = useIdPrefix(`radio-${menuGroupItem.id}`)
|
|
5
7
|
const { visibleWhen } = menuGroupItem
|
|
6
8
|
const visible = visibleWhen ? isVisibleWhen(visibleWhen) : true
|
|
7
9
|
if (!visible) {
|
|
@@ -11,7 +13,7 @@ export const LayersMenuRadio = ({ menuGroupItem, name, checked, onChange }) => {
|
|
|
11
13
|
<div className={itemClass} data-module='govuk-radios'>
|
|
12
14
|
<div className='govuk-radios__item'>
|
|
13
15
|
<input
|
|
14
|
-
id={
|
|
16
|
+
id={itemId}
|
|
15
17
|
className='govuk-radios__input'
|
|
16
18
|
type='radio'
|
|
17
19
|
name={name}
|
|
@@ -19,7 +21,7 @@ export const LayersMenuRadio = ({ menuGroupItem, name, checked, onChange }) => {
|
|
|
19
21
|
checked={checked}
|
|
20
22
|
onChange={onChange}
|
|
21
23
|
/>
|
|
22
|
-
<label className='im-c-
|
|
24
|
+
<label className='im-c-menu__item-label govuk-label govuk-radios__label' htmlFor={itemId}>
|
|
23
25
|
{menuGroupItem.label}
|
|
24
26
|
</label>
|
|
25
27
|
</div>
|
|
@@ -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
|
+
}
|