@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
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@defra/menu-plugin",
|
|
3
|
+
"version": "1.0.0-alpha.1",
|
|
4
|
+
"main": "dist/umd/index.js",
|
|
5
|
+
"module": "dist/esm/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
"import": "./dist/esm/index.js",
|
|
8
|
+
"require": "./dist/umd/index.js"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"peerDependencies": {
|
|
12
|
+
"react": "^19.2.0",
|
|
13
|
+
"react-dom": "^19.2.0",
|
|
14
|
+
"preact": "^10.27.0"
|
|
15
|
+
},
|
|
16
|
+
"peerDependenciesMeta": {
|
|
17
|
+
"react": { "optional": true },
|
|
18
|
+
"react-dom": { "optional": true }
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build:umd": "webpack --config ../../../webpack.umd.js --mode production",
|
|
22
|
+
"build:esm": "webpack --config ../../../webpack.esm.mjs --mode production",
|
|
23
|
+
"build": "npm run build:umd && npm run build:esm",
|
|
24
|
+
"clean": "rm -rf dist"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {},
|
|
27
|
+
"dependencies": {}
|
|
28
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { MenuCheckbox } from './MenuCheckbox.jsx'
|
|
3
|
+
import { GroupLegend } from './GroupLegend.jsx'
|
|
4
|
+
|
|
5
|
+
export const CheckboxGroupWrapper = ({ dispatch, menuGroup, menuState }) => {
|
|
6
|
+
return (
|
|
7
|
+
<GroupLegend menuGroup={menuGroup}> {
|
|
8
|
+
// Each menuGroupItem
|
|
9
|
+
menuGroup.items.map(menuGroupItem => (
|
|
10
|
+
<MenuCheckbox
|
|
11
|
+
key={menuGroupItem.id}
|
|
12
|
+
dispatch={dispatch}
|
|
13
|
+
menuGroupItem={menuGroupItem}
|
|
14
|
+
checked={menuState[menuGroupItem.id]}
|
|
15
|
+
onChange={menuGroupItem.handleOnChange}
|
|
16
|
+
/>)
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
</GroupLegend>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const GroupLegend = ({ menuGroup, children }) => {
|
|
2
|
+
const label = menuGroup.groupLabel || menuGroup.label
|
|
3
|
+
if (!label) {
|
|
4
|
+
return <>{children}</>
|
|
5
|
+
}
|
|
6
|
+
const wrapperClass = 'govuk-form-group im-c-menu-group'
|
|
7
|
+
return (
|
|
8
|
+
<div key={menuGroup.id} className={wrapperClass}>
|
|
9
|
+
<fieldset className='im-c-menu-group__fieldset'>
|
|
10
|
+
<legend className='im-c-menu-group__legend'>
|
|
11
|
+
<h3> {label} </h3>
|
|
12
|
+
</legend>
|
|
13
|
+
{children}
|
|
14
|
+
</fieldset>
|
|
15
|
+
</div>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react'
|
|
2
|
+
import { GroupLegend } from './GroupLegend.jsx'
|
|
3
|
+
|
|
4
|
+
const child = <span data-testid='child'>Child content</span>
|
|
5
|
+
|
|
6
|
+
describe('GroupLegend', () => {
|
|
7
|
+
describe('without a groupLabel', () => {
|
|
8
|
+
it('renders children directly without a wrapping div', () => {
|
|
9
|
+
const { getByTestId, container } = render(
|
|
10
|
+
<GroupLegend menuGroup={{ id: 'g1' }}>{child}</GroupLegend>
|
|
11
|
+
)
|
|
12
|
+
expect(getByTestId('child')).toBeTruthy()
|
|
13
|
+
expect(container.querySelector('.govuk-form-group')).toBeNull()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('does not render a fieldset when groupLabel is absent', () => {
|
|
17
|
+
const { container } = render(
|
|
18
|
+
<GroupLegend menuGroup={{ id: 'g1' }}>{child}</GroupLegend>
|
|
19
|
+
)
|
|
20
|
+
expect(container.querySelector('fieldset')).toBeNull()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('does not render a fieldset when groupLabel is an empty string', () => {
|
|
24
|
+
const { container } = render(
|
|
25
|
+
<GroupLegend menuGroup={{ id: 'g1', groupLabel: '' }}>{child}</GroupLegend>
|
|
26
|
+
)
|
|
27
|
+
expect(container.querySelector('fieldset')).toBeNull()
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
describe('with a groupLabel', () => {
|
|
32
|
+
it('renders the outer wrapper with the correct classes', () => {
|
|
33
|
+
const { container } = render(
|
|
34
|
+
<GroupLegend menuGroup={{ id: 'g1', groupLabel: 'My Group' }}>{child}</GroupLegend>
|
|
35
|
+
)
|
|
36
|
+
const wrapper = container.querySelector('.govuk-form-group.im-c-menu-group')
|
|
37
|
+
expect(wrapper).toBeTruthy()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('renders a fieldset with the correct class', () => {
|
|
41
|
+
const { container } = render(
|
|
42
|
+
<GroupLegend menuGroup={{ id: 'g1', groupLabel: 'My Group' }}>{child}</GroupLegend>
|
|
43
|
+
)
|
|
44
|
+
expect(container.querySelector('fieldset.im-c-menu-group__fieldset')).toBeTruthy()
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('renders the groupLabel as the legend text', () => {
|
|
48
|
+
render(
|
|
49
|
+
<GroupLegend menuGroup={{ id: 'g1', groupLabel: 'My Group' }}>{child}</GroupLegend>
|
|
50
|
+
)
|
|
51
|
+
expect(screen.getByText('My Group')).toBeTruthy()
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('renders the legend with the correct class', () => {
|
|
55
|
+
const { container } = render(
|
|
56
|
+
<GroupLegend menuGroup={{ id: 'g1', groupLabel: 'My Group' }}>{child}</GroupLegend>
|
|
57
|
+
)
|
|
58
|
+
expect(container.querySelector('legend.im-c-menu-group__legend')).toBeTruthy()
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('renders children inside the fieldset', () => {
|
|
62
|
+
const { getByTestId } = render(
|
|
63
|
+
<GroupLegend menuGroup={{ id: 'g1', groupLabel: 'My Group' }}>{child}</GroupLegend>
|
|
64
|
+
)
|
|
65
|
+
expect(getByTestId('child')).toBeTruthy()
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { MenuGroup } from './MenuGroup.jsx'
|
|
3
|
+
import { IdPrefixContext } from './useIdPrefix.jsx'
|
|
4
|
+
|
|
5
|
+
export const Menu = ({ pluginState, appConfig }) => {
|
|
6
|
+
const { menu = [], dispatch, menuState } = pluginState
|
|
7
|
+
const appId = appConfig?.id || 'map'
|
|
8
|
+
const hasGroups = menu.some(item => item.groupLabel)
|
|
9
|
+
const containerClass = `im-c-menu${hasGroups ? ' im-c-menu--has-groups' : ''}`
|
|
10
|
+
return (
|
|
11
|
+
<IdPrefixContext value={`${appId}-menu`}>
|
|
12
|
+
<div className={containerClass}> {
|
|
13
|
+
menu.map(menuGroup =>
|
|
14
|
+
<MenuGroup key={menuGroup.id} menuGroup={menuGroup} dispatch={dispatch} menuState={menuState} />)
|
|
15
|
+
}
|
|
16
|
+
</div>
|
|
17
|
+
</IdPrefixContext>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// When groups are present, every direct child except the first gets a border-top
|
|
2
|
+
|
|
3
|
+
.im-c-menu--has-groups > *:not(:first-child) {
|
|
4
|
+
border-top: 1px solid var(--button-hover-color);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.im-c-menu > *:first-child {
|
|
8
|
+
padding-top: 5px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.im-c-menu > *:last-child {
|
|
12
|
+
margin-bottom: -5px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.im-c-menu-group:not(:last-child) {
|
|
16
|
+
padding-bottom: 5px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.im-c-menu__item {
|
|
20
|
+
padding-bottom: 5px;
|
|
21
|
+
|
|
22
|
+
&:first-child {
|
|
23
|
+
padding-top: 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.im-c-menu--has-groups > &:not(:first-child) {
|
|
27
|
+
padding-top: 5px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Items inside a group have no individual padding or spacing between them
|
|
31
|
+
.im-c-menu-group & {
|
|
32
|
+
padding-top: 0;
|
|
33
|
+
padding-bottom: 0;
|
|
34
|
+
|
|
35
|
+
&:not(:last-child) {
|
|
36
|
+
margin-bottom: 0;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.im-c-menu__item-label {
|
|
41
|
+
width: 100%;
|
|
42
|
+
max-width: none;
|
|
43
|
+
align-items: start;
|
|
44
|
+
padding-top: 12px;
|
|
45
|
+
padding-bottom: 10px;
|
|
46
|
+
align-self: auto;
|
|
47
|
+
font-size: 1rem;
|
|
48
|
+
line-height: 1.2;
|
|
49
|
+
|
|
50
|
+
color: var(--foreground-color);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// GovUK style overide
|
|
55
|
+
.im-c-menu__item .govuk-checkboxes__item,
|
|
56
|
+
.im-c-menu__item .govuk-radios__item {
|
|
57
|
+
flex-wrap: nowrap;
|
|
58
|
+
|
|
59
|
+
.govuk-checkboxes__input, .govuk-radios__input {
|
|
60
|
+
margin-left: -3px;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.im-c-menu-group__fieldset {
|
|
65
|
+
// Reset browser fieldset defaults
|
|
66
|
+
border: none;
|
|
67
|
+
padding: 0;
|
|
68
|
+
margin: 0;
|
|
69
|
+
min-width: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.im-c-menu-group__legend {
|
|
73
|
+
padding-top: 15px;
|
|
74
|
+
padding-bottom: 10px;
|
|
75
|
+
padding-inline: 0;
|
|
76
|
+
font-size: 1rem;
|
|
77
|
+
font-weight: bold;
|
|
78
|
+
color: var(--foreground-color);
|
|
79
|
+
h3 {
|
|
80
|
+
font-size: inherit;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.im-c-menu-group:first-child .im-c-menu-group__legend {
|
|
85
|
+
padding-top: 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.im-c-menu .govuk-checkboxes__input[aria-disabled="true"] + .govuk-checkboxes__label {
|
|
89
|
+
opacity: 0.5;
|
|
90
|
+
}
|
|
@@ -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>
|