@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.
Files changed (351) hide show
  1. package/dist/css/index.css +1 -1
  2. package/dist/esm/im-core.js +1 -1
  3. package/dist/esm/im-shell.js +1 -1
  4. package/dist/umd/im-core.js +1 -1
  5. package/dist/umd/index.js +1 -1
  6. package/docs/api/control-definition.md +9 -1
  7. package/docs/api/slots.md +26 -5
  8. package/docs/assets/images/slot-map.svg +61 -262
  9. package/docs/examples/draw-tools.mdx +3 -3
  10. package/docs/plugins/draw.md +79 -16
  11. package/docs/plugins/search.md +1 -1
  12. package/govuk-prototype-kit.config.json +2 -0
  13. package/jest.setup.js +5 -0
  14. package/package.json +9 -1
  15. package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
  16. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
  17. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
  18. package/plugins/beta/draw-ol/dist/esm/im-draw-ol-plugin.js +1 -1
  19. package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -1
  20. package/plugins/beta/map-styles/dist/umd/index.js +1 -1
  21. package/plugins/datasets/dist/css/index.css +1 -1
  22. package/plugins/datasets/dist/esm/esriLayerAdapter.js +1 -1
  23. package/plugins/datasets/dist/esm/im-datasets-ml-adapter.js +1 -1
  24. package/plugins/datasets/dist/esm/im-datasets-plugin.js +1 -1
  25. package/plugins/datasets/dist/umd/im-datasets-esri-adapter.js +1 -1
  26. package/plugins/datasets/dist/umd/im-datasets-ml-adapter.js +1 -1
  27. package/plugins/datasets/dist/umd/im-datasets-plugin.js +1 -1
  28. package/plugins/datasets/dist/umd/index.js +1 -1
  29. package/plugins/datasets/src/adapters/esri/esriLayerAdapter.test.js +175 -0
  30. package/plugins/datasets/src/adapters/esri/registry/esriDataset.test.js +55 -0
  31. package/plugins/datasets/src/adapters/loadLayerAdapter.test.js +61 -0
  32. package/plugins/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js +14 -0
  33. package/plugins/datasets/src/api/setOpacity.test.js +9 -0
  34. package/plugins/datasets/src/components/LayersMenu/LayersMenu.jsx +10 -25
  35. package/plugins/datasets/src/components/LayersMenu/LayersMenu.test.jsx +0 -42
  36. package/plugins/datasets/src/datasets.scss +0 -1
  37. package/plugins/datasets/src/fetch/createDynamicSource.js +135 -129
  38. package/plugins/datasets/src/fetch/createDynamicSource.test.js +318 -0
  39. package/plugins/datasets/src/fetch/fetchGeoJSON.test.js +83 -0
  40. package/plugins/datasets/src/index.test.js +36 -0
  41. package/plugins/datasets/src/initialise/DatasetsInit.jsx +17 -7
  42. package/plugins/datasets/src/initialise/DatasetsInit.test.jsx +262 -0
  43. package/plugins/datasets/src/initialise/initialiseDatasets.js +16 -4
  44. package/plugins/datasets/src/initialise/initialiseDatasets.test.js +42 -0
  45. package/plugins/datasets/src/manifest.js +0 -38
  46. package/plugins/datasets/src/manifest.test.js +49 -0
  47. package/plugins/datasets/src/reducers/datasetsToMenu.test.js +54 -1
  48. package/plugins/datasets/src/reducers/pluginState.js +3 -16
  49. package/plugins/datasets/src/reducers/pluginState.test.js +23 -0
  50. package/plugins/datasets/src/registry/dataset.js +13 -1
  51. package/plugins/datasets/src/registry/dataset.test.js +61 -0
  52. package/plugins/datasets/src/registry/datasetRegistry.js +12 -6
  53. package/plugins/datasets/src/registry/datasetRegistry.test.js +16 -4
  54. package/plugins/datasets/src/registry/isVisibleWhen.js +6 -3
  55. package/plugins/datasets/src/registry/isVisibleWhen.test.js +11 -1
  56. package/plugins/datasets/src/utils/bbox.test.js +125 -0
  57. package/plugins/draw/dist/esm/im-draw-ml-adapter.js +1 -1
  58. package/plugins/draw/dist/esm/im-draw-ol-adapter.js +1 -1
  59. package/plugins/draw/dist/esm/im-draw-plugin.js +1 -1
  60. package/plugins/draw/dist/esm/index.js +1 -1
  61. package/plugins/draw/dist/umd/im-draw-ml-adapter.js +2 -1
  62. package/plugins/draw/dist/umd/im-draw-ml-adapter.js.LICENSE.txt +1 -0
  63. package/plugins/draw/dist/umd/im-draw-ol-adapter.js +1 -1
  64. package/plugins/draw/dist/umd/im-draw-plugin.js +1 -1
  65. package/plugins/draw/dist/umd/index.js +1 -1
  66. package/plugins/draw/src/DrawInit.jsx +10 -2
  67. package/plugins/draw/src/DrawInit.test.jsx +51 -10
  68. package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.js +91 -11
  69. package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.test.js +246 -4
  70. package/plugins/draw/src/adapters/maplibre/mapboxDraw.js +109 -14
  71. package/plugins/draw/src/adapters/maplibre/mapboxDraw.test.js +174 -11
  72. package/plugins/draw/src/adapters/maplibre/modes/drawMode/clickHandlers.test.js +12 -0
  73. package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.js +9 -1
  74. package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.test.js +24 -3
  75. package/plugins/draw/src/adapters/maplibre/modes/drawPointMode.js +194 -0
  76. package/plugins/draw/src/adapters/maplibre/modes/drawPointMode.test.js +457 -0
  77. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/__helpers__/harness.js +102 -0
  78. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/keyboardHandlers.js +82 -0
  79. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/keyboardHandlers.test.js +83 -0
  80. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointOperations.js +55 -0
  81. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointOperations.test.js +62 -0
  82. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointerHandlers.js +138 -0
  83. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointerHandlers.test.js +197 -0
  84. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/touchHandlers.js +92 -0
  85. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/touchHandlers.test.js +101 -0
  86. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/undoHandlers.js +46 -0
  87. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/undoHandlers.test.js +42 -0
  88. package/plugins/draw/src/adapters/maplibre/modes/editPointMode.js +151 -0
  89. package/plugins/draw/src/adapters/maplibre/modes/editPointMode.test.js +156 -0
  90. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.js +4 -27
  91. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.test.js +24 -39
  92. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/pointerHandlers.js +4 -5
  93. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.js +20 -23
  94. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.test.js +25 -5
  95. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.js +6 -36
  96. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.test.js +7 -49
  97. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.js +3 -53
  98. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.test.js +8 -33
  99. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.js +29 -72
  100. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.test.js +10 -3
  101. package/plugins/draw/src/adapters/maplibre/pointSymbolImages.js +158 -0
  102. package/plugins/draw/src/adapters/maplibre/pointSymbolImages.test.js +314 -0
  103. package/plugins/draw/src/adapters/maplibre/snap/prototypePatches.js +6 -1
  104. package/plugins/draw/src/adapters/maplibre/snap/prototypePatches.test.js +21 -0
  105. package/plugins/draw/src/adapters/maplibre/snap/snapInstance.js +6 -2
  106. package/plugins/draw/src/adapters/maplibre/snap/snapInstance.test.js +12 -0
  107. package/plugins/draw/src/adapters/maplibre/styles.js +38 -11
  108. package/plugins/draw/src/adapters/maplibre/styles.test.js +39 -0
  109. package/plugins/draw/src/adapters/maplibre/utils/editModeEvents.js +79 -0
  110. package/plugins/draw/src/adapters/maplibre/utils/editModeEvents.test.js +135 -0
  111. package/plugins/draw/src/adapters/maplibre/utils/geometryValidation.js +42 -0
  112. package/plugins/draw/src/adapters/maplibre/utils/geometryValidation.test.js +85 -0
  113. package/plugins/draw/src/adapters/maplibre/utils/keyboardShortcuts.js +34 -0
  114. package/plugins/draw/src/adapters/maplibre/utils/keyboardShortcuts.test.js +78 -0
  115. package/plugins/draw/src/adapters/maplibre/utils/snapHelpers.js +16 -3
  116. package/plugins/draw/src/adapters/maplibre/utils/snapHelpers.test.js +21 -3
  117. package/plugins/draw/src/adapters/maplibre/utils/snapMovement.js +59 -0
  118. package/plugins/draw/src/adapters/maplibre/utils/snapMovement.test.js +73 -0
  119. package/plugins/draw/src/adapters/maplibre/utils/touchDragMath.js +33 -0
  120. package/plugins/draw/src/adapters/maplibre/utils/touchDragMath.test.js +70 -0
  121. package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.js +27 -2
  122. package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.test.js +93 -0
  123. package/plugins/draw/src/adapters/openlayers/__helpers__/harness.js +9 -0
  124. package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.js +19 -1
  125. package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.test.js +34 -1
  126. package/plugins/draw/src/adapters/openlayers/core/styles.js +73 -1
  127. package/plugins/draw/src/adapters/openlayers/core/styles.test.js +122 -3
  128. package/plugins/draw/src/adapters/openlayers/draw/DrawMode.test.js +12 -0
  129. package/plugins/draw/src/adapters/openlayers/draw/drawInput.js +8 -2
  130. package/plugins/draw/src/adapters/openlayers/edit/EditMode.test.js +31 -0
  131. package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.js +9 -5
  132. package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.test.js +33 -0
  133. package/plugins/draw/src/adapters/openlayers/edit/modifyInteraction.js +5 -3
  134. package/plugins/draw/src/adapters/openlayers/edit/modifyInteraction.test.js +11 -0
  135. package/plugins/draw/src/adapters/openlayers/edit/nudge.js +10 -3
  136. package/plugins/draw/src/adapters/openlayers/edit/nudge.test.js +24 -1
  137. package/plugins/draw/src/adapters/openlayers/edit/touchHandler.js +18 -13
  138. package/plugins/draw/src/adapters/openlayers/edit/touchHandler.test.js +46 -1
  139. package/plugins/draw/src/adapters/openlayers/olDraw.js +11 -4
  140. package/plugins/draw/src/adapters/openlayers/olDraw.test.js +48 -6
  141. package/plugins/draw/src/adapters/openlayers/point/drawPointMode.js +156 -0
  142. package/plugins/draw/src/adapters/openlayers/point/drawPointMode.test.js +246 -0
  143. package/plugins/draw/src/adapters/openlayers/point/editPointMode.js +267 -0
  144. package/plugins/draw/src/adapters/openlayers/point/editPointMode.test.js +327 -0
  145. package/plugins/draw/src/adapters/openlayers/point/pointDragInteraction.js +71 -0
  146. package/plugins/draw/src/adapters/openlayers/point/pointOps.js +34 -0
  147. package/plugins/draw/src/adapters/openlayers/point/pointOps.test.js +32 -0
  148. package/plugins/draw/src/adapters/openlayers/point/pointSelectionState.js +82 -0
  149. package/plugins/draw/src/adapters/openlayers/point/pointSelectionState.test.js +107 -0
  150. package/plugins/draw/src/adapters/openlayers/point/pointSymbolImages.js +83 -0
  151. package/plugins/draw/src/adapters/openlayers/point/pointSymbolImages.test.js +214 -0
  152. package/plugins/draw/src/adapters/openlayers/snap/snapIndicator.js +3 -1
  153. package/plugins/draw/src/adapters/openlayers/snap/snapInteraction.js +6 -9
  154. package/plugins/draw/src/adapters/openlayers/snap/snapInteraction.test.js +15 -4
  155. package/plugins/draw/src/adapters/openlayers/utils/olCoords.js +1 -1
  156. package/plugins/draw/src/api/addFeature.js +16 -1
  157. package/plugins/draw/src/api/addFeature.test.js +62 -5
  158. package/plugins/draw/src/api/editFeature.js +7 -4
  159. package/plugins/draw/src/api/editFeature.test.js +16 -0
  160. package/plugins/draw/src/api/newPoint.js +42 -0
  161. package/plugins/draw/src/api/newPoint.test.js +117 -0
  162. package/plugins/draw/src/api/setStyle.js +43 -0
  163. package/plugins/draw/src/api/setStyle.test.js +75 -0
  164. package/plugins/draw/src/events.js +17 -10
  165. package/plugins/draw/src/events.test.js +14 -0
  166. package/plugins/draw/src/manifest.js +18 -6
  167. package/plugins/draw/src/manifest.test.js +32 -1
  168. package/plugins/draw/src/reducer.test.js +7 -0
  169. package/plugins/draw/src/utils/stripInternalProperties.js +19 -0
  170. package/plugins/draw/src/utils/stripInternalProperties.test.js +50 -0
  171. package/plugins/draw/src/utils/symbolKeys.js +5 -0
  172. package/plugins/draw/src/validation/liveDrawChecks.test.js +54 -0
  173. package/plugins/draw/src/validation/liveStroke.test.js +64 -1
  174. package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
  175. package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
  176. package/plugins/interact/dist/umd/index.js +1 -1
  177. package/plugins/interact/src/hooks/useHighlightSync.js +33 -12
  178. package/plugins/interact/src/hooks/useHighlightSync.test.js +96 -25
  179. package/plugins/interact/src/utils/featureQueries.js +18 -0
  180. package/plugins/interact/src/utils/featureQueries.test.js +15 -0
  181. package/plugins/interact/src/utils/spatial.js +9 -3
  182. package/plugins/interact/src/utils/spatial.test.js +12 -1
  183. package/plugins/map-key/dist/css/index.css +62 -0
  184. package/plugins/map-key/dist/esm/im-map-key-plugin.js +1 -0
  185. package/plugins/map-key/dist/esm/index.js +1 -0
  186. package/plugins/map-key/dist/umd/im-map-key-plugin.js +2 -0
  187. package/plugins/map-key/dist/umd/im-map-key-plugin.js.LICENSE.txt +1 -0
  188. package/plugins/map-key/dist/umd/index.js +2 -0
  189. package/plugins/map-key/dist/umd/index.js.LICENSE.txt +1 -0
  190. package/plugins/map-key/package.json +28 -0
  191. package/plugins/map-key/src/components/Key/EmptyKey.jsx +7 -0
  192. package/plugins/{datasets → map-key}/src/components/Key/EmptyKey.test.jsx +2 -2
  193. package/plugins/map-key/src/components/Key/Key.jsx +41 -0
  194. package/plugins/{datasets → map-key}/src/components/Key/Key.module.scss +15 -14
  195. package/plugins/map-key/src/components/Key/Key.test.jsx +73 -0
  196. package/plugins/map-key/src/components/Key/KeyGroupItem.jsx +16 -0
  197. package/plugins/map-key/src/components/Key/KeyGroupItem.test.jsx +53 -0
  198. package/plugins/map-key/src/components/Key/KeyItem.jsx +29 -0
  199. package/plugins/map-key/src/components/Key/KeyItem.test.jsx +67 -0
  200. package/plugins/map-key/src/components/Key/KeySvg.jsx +42 -0
  201. package/plugins/{datasets → map-key}/src/components/Key/KeySvg.test.jsx +14 -12
  202. package/plugins/map-key/src/components/Key/KeySvgLine.jsx +28 -0
  203. package/plugins/{datasets → map-key}/src/components/Key/KeySvgLine.test.jsx +1 -1
  204. package/plugins/map-key/src/components/Key/KeySvgPattern.jsx +23 -0
  205. package/plugins/{datasets → map-key}/src/components/Key/KeySvgPattern.test.jsx +2 -2
  206. package/plugins/map-key/src/components/Key/KeySvgRect.jsx +33 -0
  207. package/plugins/{datasets → map-key}/src/components/Key/KeySvgRect.test.jsx +1 -1
  208. package/plugins/map-key/src/components/Key/KeySvgSymbol.jsx +27 -0
  209. package/plugins/{datasets → map-key}/src/components/Key/KeySvgSymbol.test.jsx +5 -6
  210. package/plugins/map-key/src/components/Key/MapKey.jsx +50 -0
  211. package/plugins/map-key/src/components/Key/MapKey.test.jsx +130 -0
  212. package/plugins/{datasets → map-key}/src/components/Key/svgProperties.js +2 -2
  213. package/plugins/{datasets → map-key}/src/components/Key/svgProperties.test.js +2 -2
  214. package/plugins/map-key/src/index.js +13 -0
  215. package/plugins/map-key/src/index.test.js +31 -0
  216. package/plugins/map-key/src/initialise/MapKeyInit.jsx +15 -0
  217. package/plugins/map-key/src/initialise/MapKeyInit.test.jsx +39 -0
  218. package/plugins/map-key/src/manifest.js +30 -0
  219. package/plugins/map-key/src/manifest.test.js +63 -0
  220. package/plugins/map-key/src/mapKey.scss +4 -0
  221. package/plugins/map-key/src/registry/getDatasetRegistry.js +6 -0
  222. package/plugins/map-key/src/registry/getDatasetRegistry.test.js +23 -0
  223. package/plugins/map-key/src/registry/index.js +3 -0
  224. package/plugins/map-key/src/registry/index.test.js +15 -0
  225. package/plugins/menu/dist/css/index.css +80 -0
  226. package/plugins/menu/dist/esm/im-menu-plugin.js +1 -0
  227. package/plugins/menu/dist/esm/index.js +1 -0
  228. package/plugins/menu/dist/umd/im-menu-plugin.js +1 -0
  229. package/plugins/menu/dist/umd/index.js +2 -0
  230. package/plugins/menu/dist/umd/index.js.LICENSE.txt +1 -0
  231. package/plugins/menu/package.json +28 -0
  232. package/plugins/menu/src/components/Menu/CheckboxGroupWrapper.jsx +21 -0
  233. package/plugins/menu/src/components/Menu/GroupLegend.jsx +17 -0
  234. package/plugins/menu/src/components/Menu/GroupLegend.test.jsx +68 -0
  235. package/plugins/menu/src/components/Menu/Menu.jsx +19 -0
  236. package/plugins/menu/src/components/Menu/Menu.module.scss +90 -0
  237. package/plugins/menu/src/components/Menu/Menu.test.jsx +161 -0
  238. package/plugins/menu/src/components/Menu/MenuCheckbox.jsx +35 -0
  239. package/plugins/menu/src/components/Menu/MenuCheckbox.test.jsx +93 -0
  240. package/plugins/menu/src/components/Menu/MenuGroup.jsx +11 -0
  241. package/plugins/{datasets/src/components/LayersMenu/LayersMenuRadio.jsx → menu/src/components/Menu/MenuRadio.jsx} +6 -4
  242. package/plugins/{datasets/src/components/LayersMenu/LayersMenuRadio.test.jsx → menu/src/components/Menu/MenuRadio.test.jsx} +18 -18
  243. package/plugins/menu/src/components/Menu/RadioGroupWrapper.jsx +32 -0
  244. package/plugins/{datasets/src/components/LayersMenu/LayersRadioGroupWrapper.test.jsx → menu/src/components/Menu/RadioGroupWrapper.test.jsx} +21 -21
  245. package/plugins/menu/src/components/Menu/useIdPrefix.jsx +4 -0
  246. package/plugins/menu/src/index.js +13 -0
  247. package/plugins/menu/src/index.test.js +31 -0
  248. package/plugins/menu/src/initialise/MenuInit.jsx +24 -0
  249. package/plugins/menu/src/initialise/MenuInit.test.jsx +50 -0
  250. package/plugins/menu/src/initialise/createMenu.js +10 -0
  251. package/plugins/menu/src/initialise/createMenu.test.js +37 -0
  252. package/plugins/menu/src/manifest.js +35 -0
  253. package/plugins/menu/src/manifest.test.js +63 -0
  254. package/plugins/menu/src/menu.scss +4 -0
  255. package/plugins/menu/src/reducers/menuStateReducer.test.js +38 -0
  256. package/plugins/menu/src/reducers/pluginState.js +35 -0
  257. package/plugins/menu/src/reducers/pluginState.test.js +57 -0
  258. package/plugins/menu/src/registry/getDatasetRegistry.js +9 -0
  259. package/plugins/menu/src/registry/getDatasetRegistry.test.js +23 -0
  260. package/plugins/menu/src/registry/index.js +3 -0
  261. package/plugins/menu/src/registry/index.test.js +15 -0
  262. package/plugins/menu/src/registry/isVisibleWhen.js +43 -0
  263. package/plugins/menu/src/registry/isVisibleWhen.test.js +48 -0
  264. package/plugins/search/dist/css/index.css +1 -1
  265. package/plugins/search/dist/esm/im-search-plugin.js +1 -1
  266. package/plugins/search/dist/esm/index.js +1 -1
  267. package/plugins/search/dist/umd/im-search-plugin.js +1 -1
  268. package/plugins/search/dist/umd/index.js +1 -1
  269. package/plugins/search/src/Search.jsx +2 -3
  270. package/plugins/search/src/components/Form/Form.module.scss +9 -20
  271. package/plugins/search/src/index.js +0 -1
  272. package/plugins/search/src/index.test.js +2 -4
  273. package/plugins/search/src/manifest.js +1 -1
  274. package/plugins/search/src/search.scss +17 -16
  275. package/providers/beta/openlayers/dist/esm/im-openlayers-provider.js +1 -1
  276. package/providers/beta/openlayers/dist/umd/im-openlayers-provider.js +1 -1
  277. package/providers/beta/openlayers/dist/umd/index.js +1 -1
  278. package/providers/beta/openlayers/src/openlayersProvider.js +4 -1
  279. package/providers/beta/openlayers/src/openlayersProvider.test.js +18 -0
  280. package/providers/beta/openlayers/src/utils/highlightFeatures.js +52 -5
  281. package/providers/beta/openlayers/src/utils/highlightFeatures.test.js +176 -0
  282. package/providers/beta/openlayers/src/utils/symbolImages.js +40 -0
  283. package/providers/beta/openlayers/src/utils/symbolImages.test.js +58 -0
  284. package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
  285. package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
  286. package/providers/maplibre/dist/umd/index.js +1 -1
  287. package/providers/maplibre/src/utils/drawLayerBuckets.js +14 -0
  288. package/providers/maplibre/src/utils/drawLayerBuckets.test.js +18 -0
  289. package/providers/maplibre/src/utils/highlightFeatures.js +80 -55
  290. package/providers/maplibre/src/utils/highlightFeatures.test.js +156 -17
  291. package/providers/maplibre/src/utils/hoverCursor.js +30 -14
  292. package/providers/maplibre/src/utils/hoverCursor.test.js +35 -0
  293. package/providers/maplibre/src/utils/patternImages.js +1 -1
  294. package/providers/maplibre/src/utils/symbolImages.js +41 -3
  295. package/providers/maplibre/src/utils/symbolImages.test.js +40 -6
  296. package/rollup.esm.mjs +11 -1
  297. package/src/App/components/Actions/Actions.test.jsx +47 -0
  298. package/src/App/components/Hints/Hints.test.jsx +13 -0
  299. package/src/App/components/MoveControls/MoveControls.module.scss +41 -10
  300. package/src/App/components/Panel/Panel.jsx +18 -3
  301. package/src/App/components/Panel/Panel.module.scss +18 -8
  302. package/src/App/components/Panel/Panel.test.jsx +34 -0
  303. package/src/App/components/Tooltip/Tooltip.test.jsx +12 -14
  304. package/src/App/hooks/useFeatureItems.js +16 -7
  305. package/src/App/hooks/useFeatureItems.test.js +57 -0
  306. package/src/App/hooks/useLayoutMeasurements.js +95 -84
  307. package/src/App/hooks/useLayoutMeasurements.test.js +61 -1
  308. package/src/App/layout/Layout.jsx +9 -10
  309. package/src/App/layout/Layout.test.jsx +2 -0
  310. package/src/App/layout/layout.module.scss +31 -17
  311. package/src/App/registry/pluginRegistry.js +1 -1
  312. package/src/App/registry/pluginRegistry.test.js +12 -0
  313. package/src/App/renderer/HtmlElementHost.jsx +18 -5
  314. package/src/App/renderer/HtmlElementHost.test.jsx +54 -0
  315. package/src/App/renderer/mapButtons.js +28 -12
  316. package/src/App/renderer/mapButtons.test.js +17 -4
  317. package/src/App/renderer/mapControls.js +3 -1
  318. package/src/App/renderer/mapControls.test.js +16 -0
  319. package/src/App/renderer/mapPanels.js +44 -9
  320. package/src/App/renderer/mapPanels.test.js +51 -2
  321. package/src/App/renderer/orderItems.js +28 -0
  322. package/src/App/renderer/orderItems.test.js +50 -0
  323. package/src/App/renderer/slotAggregator.js +2 -18
  324. package/src/App/renderer/slotHelpers.js +3 -1
  325. package/src/App/renderer/slotHelpers.test.js +5 -0
  326. package/src/App/renderer/slots.js +3 -0
  327. package/src/App/store/AppProvider.jsx +1 -0
  328. package/src/App/store/appDispatchMiddleware.js +1 -1
  329. package/src/App/store/appDispatchMiddleware.test.js +8 -0
  330. package/src/config/events.js +2 -0
  331. package/src/scss/settings/_colors.scss +1 -0
  332. package/src/scss/settings/_dimensions.scss +2 -3
  333. package/src/scss/settings/_transition.scss +1 -1
  334. package/src/services/eventBus.js +44 -0
  335. package/src/services/eventBus.test.js +83 -0
  336. package/src/services/symbolRegistry.js +1 -1
  337. package/src/types.js +11 -1
  338. package/webpack.umd.mjs +2 -0
  339. package/plugins/datasets/src/components/Key/EmptyKey.jsx +0 -7
  340. package/plugins/datasets/src/components/Key/Key.jsx +0 -50
  341. package/plugins/datasets/src/components/Key/KeyGroupItem.jsx +0 -18
  342. package/plugins/datasets/src/components/Key/KeyItem.jsx +0 -23
  343. package/plugins/datasets/src/components/Key/KeySvg.jsx +0 -22
  344. package/plugins/datasets/src/components/Key/KeySvgLine.jsx +0 -19
  345. package/plugins/datasets/src/components/Key/KeySvgPattern.jsx +0 -13
  346. package/plugins/datasets/src/components/Key/KeySvgRect.jsx +0 -22
  347. package/plugins/datasets/src/components/Key/KeySvgSymbol.jsx +0 -16
  348. package/plugins/datasets/src/components/LayersMenu/LayersRadioGroupWrapper.jsx +0 -41
  349. /package/plugins/{datasets → menu}/src/reducers/menuStateReducer.js +0 -0
  350. /package/{providers/maplibre/src → src}/utils/rasteriseToImageData.js +0 -0
  351. /package/{providers/maplibre/src → src}/utils/rasteriseToImageData.test.js +0 -0
@@ -0,0 +1,39 @@
1
+ import { render } from '@testing-library/react'
2
+ import { MapKeyInit } from './MapKeyInit.jsx'
3
+ import { setDatasetRegistry } from '../registry/getDatasetRegistry.js'
4
+
5
+ jest.mock('../registry/getDatasetRegistry.js', () => ({
6
+ setDatasetRegistry: jest.fn()
7
+ }))
8
+
9
+ const eventBus = { requestOnce: jest.fn() }
10
+ const services = { eventBus }
11
+
12
+ beforeEach(() => {
13
+ jest.clearAllMocks()
14
+ })
15
+
16
+ describe('MapKeyInit', () => {
17
+ it('does not call requestOnce when map is not ready', () => {
18
+ render(<MapKeyInit mapState={{ isMapReady: false }} services={services} />)
19
+ expect(eventBus.requestOnce).not.toHaveBeenCalled()
20
+ })
21
+
22
+ it('calls requestOnce for datasets:registry when map is ready', () => {
23
+ render(<MapKeyInit mapState={{ isMapReady: true }} services={services} />)
24
+ expect(eventBus.requestOnce).toHaveBeenCalledWith('datasets:registry', setDatasetRegistry)
25
+ })
26
+
27
+ it('calls requestOnce when isMapReady changes to true', () => {
28
+ const { rerender } = render(<MapKeyInit mapState={{ isMapReady: false }} services={services} />)
29
+ expect(eventBus.requestOnce).not.toHaveBeenCalled()
30
+ rerender(<MapKeyInit mapState={{ isMapReady: true }} services={services} />)
31
+ expect(eventBus.requestOnce).toHaveBeenCalledTimes(1)
32
+ })
33
+
34
+ it('does not call requestOnce again on re-render when isMapReady stays true', () => {
35
+ const { rerender } = render(<MapKeyInit mapState={{ isMapReady: true }} services={services} />)
36
+ rerender(<MapKeyInit mapState={{ isMapReady: true }} services={services} />)
37
+ expect(eventBus.requestOnce).toHaveBeenCalledTimes(1)
38
+ })
39
+ })
@@ -0,0 +1,30 @@
1
+ import { MapKey } from './components/Key/MapKey.jsx'
2
+ import { MapKeyInit } from './initialise/MapKeyInit.jsx'
3
+
4
+ export const manifest = {
5
+ InitComponent: MapKeyInit,
6
+ panels: [
7
+ {
8
+ id: 'mapKey',
9
+ label: 'Key',
10
+ mobile: { slot: 'drawer', modal: true },
11
+ tablet: { slot: 'left-top', width: '260px' },
12
+ desktop: { slot: 'left-top', width: '280px' },
13
+ render: MapKey
14
+ }],
15
+
16
+ buttons: [{
17
+ id: 'mapKey',
18
+ panelId: 'mapKey',
19
+ label: 'Key',
20
+ iconId: 'key',
21
+ mobile: { slot: 'top-left', showLabel: false },
22
+ tablet: { slot: 'top-left', showLabel: true },
23
+ desktop: { slot: 'top-left', showLabel: true }
24
+ }],
25
+
26
+ icons: [{
27
+ id: 'key',
28
+ svgContent: '<path d="M3 5h.01"/><path d="M3 12h.01"/><path d="M3 19h.01"/><path d="M8 5h13"/><path d="M8 12h13"/><path d="M8 19h13"/>'
29
+ }]
30
+ }
@@ -0,0 +1,63 @@
1
+ import { manifest } from './manifest.js'
2
+ import { MapKey } from './components/Key/MapKey.jsx'
3
+ import { MapKeyInit } from './initialise/MapKeyInit.jsx'
4
+
5
+ jest.mock('./components/Key/MapKey.jsx', () => ({ MapKey: jest.fn() }))
6
+ jest.mock('./initialise/MapKeyInit.jsx', () => ({ MapKeyInit: jest.fn() }))
7
+ jest.mock('./registry/getDatasetRegistry.js', () => ({}))
8
+
9
+ describe('manifest', () => {
10
+ it('sets InitComponent to MapKeyInit', () => {
11
+ expect(manifest.InitComponent).toBe(MapKeyInit)
12
+ })
13
+
14
+ describe('panels', () => {
15
+ it('defines one panel', () => {
16
+ expect(manifest.panels).toHaveLength(1)
17
+ })
18
+
19
+ it('panel has id mapKey', () => {
20
+ expect(manifest.panels[0].id).toBe('mapKey')
21
+ })
22
+
23
+ it('panel render is MapKey', () => {
24
+ expect(manifest.panels[0].render).toBe(MapKey)
25
+ })
26
+
27
+ it('panel defines mobile, tablet and desktop slots', () => {
28
+ const { mobile, tablet, desktop } = manifest.panels[0]
29
+ expect(mobile.slot).toBe('drawer')
30
+ expect(tablet.slot).toBe('left-top')
31
+ expect(desktop.slot).toBe('left-top')
32
+ })
33
+ })
34
+
35
+ describe('buttons', () => {
36
+ it('defines one button', () => {
37
+ expect(manifest.buttons).toHaveLength(1)
38
+ })
39
+
40
+ it('button has id mapKey and links to the mapKey panel', () => {
41
+ expect(manifest.buttons[0].id).toBe('mapKey')
42
+ expect(manifest.buttons[0].panelId).toBe('mapKey')
43
+ })
44
+
45
+ it('button references the key icon', () => {
46
+ expect(manifest.buttons[0].iconId).toBe('key')
47
+ })
48
+ })
49
+
50
+ describe('icons', () => {
51
+ it('defines one icon', () => {
52
+ expect(manifest.icons).toHaveLength(1)
53
+ })
54
+
55
+ it('icon id matches the button iconId', () => {
56
+ expect(manifest.icons[0].id).toBe(manifest.buttons[0].iconId)
57
+ })
58
+
59
+ it('icon has svgContent', () => {
60
+ expect(manifest.icons[0].svgContent).toBeTruthy()
61
+ })
62
+ })
63
+ })
@@ -0,0 +1,4 @@
1
+ // ===================================================
2
+ // Component: MapKey
3
+ // ===================================================
4
+ @use './components/Key/Key.module';
@@ -0,0 +1,6 @@
1
+ // the local _datasetRegistry will only be initialised if the datasets plugin is in use,
2
+ // otherwise it will remain null.
3
+ let _datasetRegistry = null
4
+
5
+ export const getDatasetRegistry = () => _datasetRegistry
6
+ export const setDatasetRegistry = (datasetRegistry) => (_datasetRegistry = datasetRegistry)
@@ -0,0 +1,23 @@
1
+ import { getDatasetRegistry, setDatasetRegistry } from './getDatasetRegistry.js'
2
+
3
+ afterEach(() => {
4
+ setDatasetRegistry(null)
5
+ })
6
+
7
+ describe('getDatasetRegistry', () => {
8
+ it('returns null before any registry is set', () => {
9
+ expect(getDatasetRegistry()).toBeNull()
10
+ })
11
+
12
+ it('returns the registry after setDatasetRegistry is called', () => {
13
+ const registry = { keyItems: jest.fn() }
14
+ setDatasetRegistry(registry)
15
+ expect(getDatasetRegistry()).toBe(registry)
16
+ })
17
+
18
+ it('returns null after being reset to null', () => {
19
+ setDatasetRegistry({ keyItems: jest.fn() })
20
+ setDatasetRegistry(null)
21
+ expect(getDatasetRegistry()).toBeNull()
22
+ })
23
+ })
@@ -0,0 +1,3 @@
1
+ export { getDatasetRegistry } from './getDatasetRegistry.js'
2
+ export { patternRegistry } from '../../../../src/services/patternRegistry.js'
3
+ export { symbolRegistry } from '../../../../src/services/symbolRegistry.js'
@@ -0,0 +1,15 @@
1
+ import { getDatasetRegistry, patternRegistry, symbolRegistry } from './index.js'
2
+
3
+ describe('registry/index', () => {
4
+ it('exports getDatasetRegistry as a function', () => {
5
+ expect(typeof getDatasetRegistry).toBe('function')
6
+ })
7
+
8
+ it('exports patternRegistry', () => {
9
+ expect(patternRegistry).toBeDefined()
10
+ })
11
+
12
+ it('exports symbolRegistry', () => {
13
+ expect(symbolRegistry).toBeDefined()
14
+ })
15
+ })
@@ -0,0 +1,80 @@
1
+ .im-c-menu--has-groups > *:not(:first-child) {
2
+ border-top: 1px solid var(--button-hover-color);
3
+ }
4
+
5
+ .im-c-menu > *:first-child {
6
+ padding-top: 5px;
7
+ }
8
+
9
+ .im-c-menu > *:last-child {
10
+ margin-bottom: -5px;
11
+ }
12
+
13
+ .im-c-menu-group:not(:last-child) {
14
+ padding-bottom: 5px;
15
+ }
16
+
17
+ .im-c-menu__item {
18
+ padding-bottom: 5px;
19
+ }
20
+ .im-c-menu__item:first-child {
21
+ padding-top: 0;
22
+ }
23
+ .im-c-menu--has-groups > .im-c-menu__item:not(:first-child) {
24
+ padding-top: 5px;
25
+ }
26
+ .im-c-menu-group .im-c-menu__item {
27
+ padding-top: 0;
28
+ padding-bottom: 0;
29
+ }
30
+ .im-c-menu-group .im-c-menu__item:not(:last-child) {
31
+ margin-bottom: 0;
32
+ }
33
+ .im-c-menu__item .im-c-menu__item-label {
34
+ width: 100%;
35
+ max-width: none;
36
+ align-items: start;
37
+ padding-top: 12px;
38
+ padding-bottom: 10px;
39
+ align-self: auto;
40
+ font-size: 1rem;
41
+ line-height: 1.2;
42
+ color: var(--foreground-color);
43
+ }
44
+
45
+ .im-c-menu__item .govuk-checkboxes__item,
46
+ .im-c-menu__item .govuk-radios__item {
47
+ flex-wrap: nowrap;
48
+ }
49
+ .im-c-menu__item .govuk-checkboxes__item .govuk-checkboxes__input, .im-c-menu__item .govuk-checkboxes__item .govuk-radios__input,
50
+ .im-c-menu__item .govuk-radios__item .govuk-checkboxes__input,
51
+ .im-c-menu__item .govuk-radios__item .govuk-radios__input {
52
+ margin-left: -3px;
53
+ }
54
+
55
+ .im-c-menu-group__fieldset {
56
+ border: none;
57
+ padding: 0;
58
+ margin: 0;
59
+ min-width: 0;
60
+ }
61
+
62
+ .im-c-menu-group__legend {
63
+ padding-top: 15px;
64
+ padding-bottom: 10px;
65
+ padding-inline: 0;
66
+ font-size: 1rem;
67
+ font-weight: bold;
68
+ color: var(--foreground-color);
69
+ }
70
+ .im-c-menu-group__legend h3 {
71
+ font-size: inherit;
72
+ }
73
+
74
+ .im-c-menu-group:first-child .im-c-menu-group__legend {
75
+ padding-top: 0;
76
+ }
77
+
78
+ .im-c-menu .govuk-checkboxes__input[aria-disabled=true] + .govuk-checkboxes__label {
79
+ opacity: 0.5;
80
+ }
@@ -0,0 +1 @@
1
+ import{createContext as e,useContext as t,useRef as a,useEffect as n}from"preact/compat";import{jsx as r,jsxs as i,Fragment as u}from"preact/jsx-runtime";import o from"@babel/runtime/helpers/defineProperty";var l={},c=e=>{var t,a=(null===(t=l)||void 0===t||null===(t=t.current)||void 0===t?void 0:t.menuState)||{};for(var[n,r]of Object.entries(e)){var i=a[n];if(!r.includes(i))return!1}return!0},m=e=>{if(null==e)return!0;if("boolean"==typeof e)return e;if("object"==typeof e){for(var[t,a]of Object.entries(e))if("menu"===t&&!c(a))return!1;return!0}return!0},s=e("map-menu"),d=e=>"".concat(t(s),"-").concat(e),p=e=>{var{menuGroupItem:t,name:a,checked:n,onChange:u}=e,o=d("radio-".concat(t.id)),{visibleWhen:l}=t;return!l||m(l)?r("div",{className:'im-c-menu__item govuk-radios govuk-radios--small"',"data-module":"govuk-radios",children:i("div",{className:"govuk-radios__item",children:[r("input",{id:o,className:"govuk-radios__input",type:"radio",name:a,value:t.id,checked:n,onChange:u}),r("label",{className:"im-c-menu__item-label govuk-label govuk-radios__label",htmlFor:o,children:t.label})]})}):null},h=e=>{var{menuGroup:t,children:a}=e,n=t.groupLabel||t.label;if(!n)return r(u,{children:a});return r("div",{className:"govuk-form-group im-c-menu-group",children:i("fieldset",{className:"im-c-menu-group__fieldset",children:[r("legend",{className:"im-c-menu-group__legend",children:i("h3",{children:[" ",n," "]})}),a]})},t.id)},v=e=>{var{menuState:t,dispatch:a,menuGroup:n}=e,{id:i,items:u,visibleWhen:o}=n;if(!(!o||m(o)))return null;var l=t[i],c=e=>{a({type:"UPDATE_MENU_STATE",payload:{[i]:e.target.value}})};return r(h,{menuGroup:n,children:r("div",{className:"govuk-radios govuk-radios--small","data-module":"govuk-radios",children:u.map(e=>r(p,{menuGroupItem:e,name:i,checked:e.id===l,onChange:c},e.id))})})},b=e=>{var{dispatch:t,menuGroupItem:a,onChange:n,checked:u}=e,o="im-c-menu__item govuk-checkboxes govuk-checkboxes--small".concat(u?"":" im-c-menu__item--checked"),l=d("checkbox-".concat(a.id));return r("div",{className:o,"data-module":"govuk-checkboxes",children:i("div",{className:"govuk-checkboxes__item",children:[r("input",{className:"govuk-checkboxes__input",id:l,name:l,type:"checkbox",checked:u,onChange:e=>{var r,i=Boolean(null===(r=e.target)||void 0===r?void 0:r.checked);n&&n(i),t({type:"UPDATE_MENU_STATE",payload:{[a.id]:i}})}}),r("label",{className:"im-c-menu__item-label govuk-label govuk-checkboxes__label",htmlFor:l,children:a.label})]})},l)},g=e=>{var{dispatch:t,menuGroup:a,menuState:n}=e;return i(h,{menuGroup:a,children:[" ",a.items.map(e=>r(b,{dispatch:t,menuGroupItem:e,checked:n[e.id],onChange:e.handleOnChange},e.id))]})},f=e=>{var{menuGroup:t,dispatch:a,menuState:n}=e;return"checkbox"===t.type?r(g,{menuGroup:t,dispatch:a,menuState:n}):r(v,{menuGroup:t,dispatch:a,menuState:n})},k=e=>{};function _(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,n)}return a}function y(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?_(Object(a),!0).forEach(function(t){o(e,t,a[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):_(Object(a)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))})}return e}var S={InitComponent:function(e){var{pluginConfig:t,pluginState:r,mapState:i,services:u}=e,{dispatch:o}=r,{eventBus:c}=u,m=a(r);m.current=r,n(()=>{if(!i.isMapReady)return()=>{};(e=>{l=e})(m);var{menu:e}=t;return(e=>{var{menu:t,eventBus:a,dispatch:n,pluginStateRef:r}=e;return n({type:"SET_MENU",payload:{menu:t}}),a.requestOnce("datasets:registry",k),a.emitWhenRequested("menu:state",r)})({menu:e,eventBus:c,dispatch:o,pluginStateRef:m})},[i.isMapReady]),n(()=>c.emit("menu:changed",r.menuState),[r.menuState])},reducer:{initialState:{actionsArray:[],menu:[],menuState:{}},actions:{SET_MENU:(e,t)=>{var{menu:a}=t,n=(e=>{var t={};return e.forEach(e=>{var a;"radio"===e.type&&(t[e.id]=e.value||(null===(a=e.items)||void 0===a?void 0:a[0].value))}),t})(a);return y(y({},e),{},{menu:a,menuState:n})},UPDATE_MENU_STATE:(e,t)=>y(y({},e),{},{menuState:y(y({},e.menuState),t)})}},panels:[{id:"menu",label:"Layers",mobile:{slot:"drawer",modal:!0,dismissible:!0},tablet:{slot:"left-top",dismissible:!0,exclusive:!0,width:"260px"},desktop:{slot:"left-top",modal:!1,dismissible:!0,exclusive:!0,width:"280px"},render:e=>{var{pluginState:t,appConfig:a}=e,{menu:n=[],dispatch:u,menuState:o}=t,l=(null==a?void 0:a.id)||"map",c=n.some(e=>e.groupLabel),m="im-c-menu".concat(c?" im-c-menu--has-groups":"");return r(s,{value:"".concat(l,"-menu"),children:i("div",{className:m,children:[" ",n.map(e=>r(f,{menuGroup:e,dispatch:u,menuState:o},e.id))]})})}}],buttons:[{id:"menuButton",label:"Layers",panelId:"menu",iconId:"layersMenu",mobile:{slot:"top-left",showLabel:!0},tablet:{slot:"top-left",showLabel:!0},desktop:{slot:"top-left",showLabel:!0}}],icons:[{id:"layersMenu",svgContent:'<path d="M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z"></path><path d="M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12"></path><path d="M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17"></path>'}]};export{S as manifest};
@@ -0,0 +1 @@
1
+ import e from"@babel/runtime/helpers/asyncToGenerator";import r from"@babel/runtime/helpers/defineProperty";function t(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter(function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable})),t.push.apply(t,n)}return t}function n(e){for(var n=1;n<arguments.length;n++){var o=null!=arguments[n]?arguments[n]:{};n%2?t(Object(o),!0).forEach(function(t){r(e,t,o[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(o)):t(Object(o)).forEach(function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(o,r))})}return e}function o(){var r;return n(n({noKeyItemText:"No features displayed"},arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),{},{id:"menu",load:(r=e(function*(){return(yield import(/* webpackChunkName: "im-menu-plugin" */ "./im-menu-plugin.js")).manifest}),function(){return r.apply(this,arguments)})})}export{o as default};
@@ -0,0 +1 @@
1
+ "use strict";(this.webpackChunkdefra_DefraMap=this.webpackChunkdefra_DefraMap||[]).push([[217],{77(e,t,n){n.r(t),n.d(t,{manifest:()=>w});var r=n(738);function o(e){return o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o(e)}function i(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,o,i,u,a=[],c=!0,l=!1;try{if(i=(n=n.call(e)).next,0===t){if(Object(n)!==n)return;c=!1}else for(;!(c=(r=i.call(n)).done)&&(a.push(r.value),a.length!==t);c=!0);}catch(e){l=!0,o=e}finally{try{if(!c&&null!=n.return&&(u=n.return(),Object(u)!==u))return}finally{if(l)throw o}}return a}}(e,t)||function(e,t){if(e){if("string"==typeof e)return u(e,t);var n={}.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?u(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function u(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}var a={},c=function(e){for(var t,n=(null===(t=a)||void 0===t||null===(t=t.current)||void 0===t?void 0:t.menuState)||{},r=0,o=Object.entries(e);r<o.length;r++){var u=i(o[r],2),c=u[0],l=u[1],s=n[c];if(!l.includes(s))return!1}return!0},l=function(e){if(null==e)return!0;if("boolean"==typeof e)return e;if("object"===o(e)){for(var t=0,n=Object.entries(e);t<n.length;t++){var r=i(n[t],2),u=r[0],a=r[1];if("menu"===u&&!c(a))return!1}return!0}return!0},s=(0,r.createContext)("map-menu"),m=function(e){return"".concat((0,r.useContext)(s),"-").concat(e)},f=n(287),p=function(e){var t=e.menuGroupItem,n=e.name,r=e.checked,o=e.onChange,i=m("radio-".concat(t.id)),u=t.visibleWhen;return!u||l(u)?(0,f.jsx)("div",{className:'im-c-menu__item govuk-radios govuk-radios--small"',"data-module":"govuk-radios",children:(0,f.jsxs)("div",{className:"govuk-radios__item",children:[(0,f.jsx)("input",{id:i,className:"govuk-radios__input",type:"radio",name:n,value:t.id,checked:r,onChange:o}),(0,f.jsx)("label",{className:"im-c-menu__item-label govuk-label govuk-radios__label",htmlFor:i,children:t.label})]})}):null},d=function(e){var t=e.menuGroup,n=e.children,r=t.groupLabel||t.label;return r?(0,f.jsx)("div",{className:"govuk-form-group im-c-menu-group",children:(0,f.jsxs)("fieldset",{className:"im-c-menu-group__fieldset",children:[(0,f.jsx)("legend",{className:"im-c-menu-group__legend",children:(0,f.jsxs)("h3",{children:[" ",r," "]})}),n]})},t.id):(0,f.jsx)(f.Fragment,{children:n})};function b(e){return b="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},b(e)}var v=function(e){var t=e.menuState,n=e.dispatch,r=e.menuGroup,o=r.id,i=r.items,u=r.visibleWhen;if(u&&!l(u))return null;var a=t[o],c=function(e){var t,r,i;n({type:"UPDATE_MENU_STATE",payload:(t={},r=o,i=e.target.value,(r=function(e){var t=function(e){if("object"!=b(e)||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!=b(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==b(t)?t:t+""}(r))in t?Object.defineProperty(t,r,{value:i,enumerable:!0,configurable:!0,writable:!0}):t[r]=i,t)})};return(0,f.jsx)(d,{menuGroup:r,children:(0,f.jsx)("div",{className:"govuk-radios govuk-radios--small","data-module":"govuk-radios",children:i.map(function(e){return(0,f.jsx)(p,{menuGroupItem:e,name:o,checked:e.id===a,onChange:c},e.id)})})})};function y(e){return y="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},y(e)}var h=function(e){var t=e.dispatch,n=e.menuGroupItem,r=e.onChange,o=e.checked,i="im-c-menu__item govuk-checkboxes govuk-checkboxes--small".concat(o?"":" im-c-menu__item--checked"),u=m("checkbox-".concat(n.id));return(0,f.jsx)("div",{className:i,"data-module":"govuk-checkboxes",children:(0,f.jsxs)("div",{className:"govuk-checkboxes__item",children:[(0,f.jsx)("input",{className:"govuk-checkboxes__input",id:u,name:u,type:"checkbox",checked:o,onChange:function(e){var o,i,u,a,c=Boolean(null===(o=e.target)||void 0===o?void 0:o.checked);r&&r(c),t({type:"UPDATE_MENU_STATE",payload:(i={},u=n.id,a=c,(u=function(e){var t=function(e){if("object"!=y(e)||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!=y(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==y(t)?t:t+""}(u))in i?Object.defineProperty(i,u,{value:a,enumerable:!0,configurable:!0,writable:!0}):i[u]=a,i)})}}),(0,f.jsx)("label",{className:"im-c-menu__item-label govuk-label govuk-checkboxes__label",htmlFor:u,children:n.label})]})},u)},g=function(e){var t=e.dispatch,n=e.menuGroup,r=e.menuState;return(0,f.jsxs)(d,{menuGroup:n,children:[" ",n.items.map(function(e){return(0,f.jsx)(h,{dispatch:t,menuGroupItem:e,checked:r[e.id],onChange:e.handleOnChange},e.id)})]})},S=function(e){var t=e.menuGroup,n=e.dispatch,r=e.menuState;return"checkbox"===t.type?(0,f.jsx)(g,{menuGroup:t,dispatch:n,menuState:r}):(0,f.jsx)(v,{menuGroup:t,dispatch:n,menuState:r})},j=function(e){};function k(e){return k="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},k(e)}function x(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function _(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?x(Object(n),!0).forEach(function(t){O(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):x(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function O(e,t,n){return(t=function(e){var t=function(e){if("object"!=k(e)||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!=k(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==k(t)?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var w={InitComponent:function(e){var t=e.pluginConfig,n=e.pluginState,o=e.mapState,i=e.services,u=n.dispatch,c=i.eventBus,l=(0,r.useRef)(n);l.current=n,(0,r.useEffect)(function(){return o.isMapReady?(function(e){a=e}(l),function(e){var t=e.eventBus,n=e.pluginStateRef;return(0,e.dispatch)({type:"SET_MENU",payload:{menu:e.menu}}),t.requestOnce("datasets:registry",j),t.emitWhenRequested("menu:state",n)}({menu:t.menu,eventBus:c,dispatch:u,pluginStateRef:l})):function(){}},[o.isMapReady]),(0,r.useEffect)(function(){return c.emit("menu:changed",n.menuState)},[n.menuState])},reducer:{initialState:{actionsArray:[],menu:[],menuState:{}},actions:{SET_MENU:function(e,t){var n=t.menu,r=function(e){var t={};return e.forEach(function(e){var n;"radio"===e.type&&(t[e.id]=e.value||(null===(n=e.items)||void 0===n?void 0:n[0].value))}),t}(n);return _(_({},e),{},{menu:n,menuState:r})},UPDATE_MENU_STATE:function(e,t){return _(_({},e),{},{menuState:_(_({},e.menuState),t)})}}},panels:[{id:"menu",label:"Layers",mobile:{slot:"drawer",modal:!0,dismissible:!0},tablet:{slot:"left-top",dismissible:!0,exclusive:!0,width:"260px"},desktop:{slot:"left-top",modal:!1,dismissible:!0,exclusive:!0,width:"280px"},render:function(e){var t=e.pluginState,n=e.appConfig,r=t.menu,o=void 0===r?[]:r,i=t.dispatch,u=t.menuState,a=(null==n?void 0:n.id)||"map",c=o.some(function(e){return e.groupLabel}),l="im-c-menu".concat(c?" im-c-menu--has-groups":"");return(0,f.jsx)(s,{value:"".concat(a,"-menu"),children:(0,f.jsxs)("div",{className:l,children:[" ",o.map(function(e){return(0,f.jsx)(S,{menuGroup:e,dispatch:i,menuState:u},e.id)})]})})}}],buttons:[{id:"menuButton",label:"Layers",panelId:"menu",iconId:"layersMenu",mobile:{slot:"top-left",showLabel:!0},tablet:{slot:"top-left",showLabel:!0},desktop:{slot:"top-left",showLabel:!0}}],icons:[{id:"layersMenu",svgContent:'<path d="M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z"></path><path d="M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12"></path><path d="M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17"></path>'}]}}}]);
@@ -0,0 +1,2 @@
1
+ /*! For license information please see index.js.LICENSE.txt */
2
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("defra",[],t):"object"==typeof exports?exports.defra=t():(e.defra=e.defra||{},e.defra.menuPlugin=t())}(this,()=>(()=>{"use strict";var e,t,r={738(e){e.exports=preactCompat},287(e){e.exports=preactJsxRuntime}},n={};function o(e){var t=n[e];if(void 0!==t)return t.exports;var i=n[e]={exports:{}};return r[e](i,i.exports,o),i.exports}o.m=r,o.d=(e,t)=>{for(var r in t)o.o(t,r)&&!o.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce((t,r)=>(o.f[r](e,t),t),[])),o.u=e=>"im-menu-plugin.js",o.miniCssF=e=>{},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),e={},t="defra.menuPlugin:",o.l=(r,n,i,a)=>{if(e[r])e[r].push(n);else{var u,c;if(void 0!==i)for(var f=document.getElementsByTagName("script"),p=0;p<f.length;p++){var l=f[p];if(l.getAttribute("src")==r||l.getAttribute("data-webpack")==t+i){u=l;break}}u||(c=!0,(u=document.createElement("script")).charset="utf-8",o.nc&&u.setAttribute("nonce",o.nc),u.setAttribute("data-webpack",t+i),u.src=r),e[r]=[n];var s=(t,n)=>{u.onerror=u.onload=null,clearTimeout(d);var o=e[r];if(delete e[r],u.parentNode&&u.parentNode.removeChild(u),o&&o.forEach(e=>e(n)),t)return t(n)},d=setTimeout(s.bind(null,void 0,{type:"timeout",target:u}),12e4);u.onerror=s.bind(null,u.onerror),u.onload=s.bind(null,u.onload),c&&document.head.appendChild(u)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+"");var t=o.g.document;if(!e&&t&&(t.currentScript&&"SCRIPT"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName("script");if(r.length)for(var n=r.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=r[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),o.p=e})(),(()=>{var e={57:0};o.f.j=(t,r)=>{var n=o.o(e,t)?e[t]:void 0;if(0!==n)if(n)r.push(n[2]);else{var i=new Promise((r,o)=>n=e[t]=[r,o]);r.push(n[2]=i);var a=o.p+o.u(t),u=new Error;o.l(a,r=>{if(o.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var i=r&&("load"===r.type?"missing":r.type),a=r&&r.target&&r.target.src;u.message="Loading chunk "+t+" failed.\n("+i+": "+a+")",u.name="ChunkLoadError",u.type=i,u.request=a,n[1](u)}},"chunk-"+t,t)}};var t=(t,r)=>{var n,i,[a,u,c]=r,f=0;if(a.some(t=>0!==e[t])){for(n in u)o.o(u,n)&&(o.m[n]=u[n]);c&&c(o)}for(t&&t(r);f<a.length;f++)i=a[f],o.o(e,i)&&e[i]&&e[i][0](),e[i]=0},r=this.webpackChunkdefra_DefraMap=this.webpackChunkdefra_DefraMap||[];r.forEach(t.bind(null,0)),r.push=t.bind(null,r.push.bind(r))})();var i={};function a(e){return a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a(e)}function u(){var e,t,r="function"==typeof Symbol?Symbol:{},n=r.iterator||"@@iterator",o=r.toStringTag||"@@toStringTag";function i(r,n,o,i){var u=n&&n.prototype instanceof f?n:f,p=Object.create(u.prototype);return c(p,"_invoke",function(r,n,o){var i,u,c,f=0,p=o||[],l=!1,s={p:0,n:0,v:e,a:d,f:d.bind(e,4),d:function(t,r){return i=t,u=0,c=e,s.n=r,a}};function d(r,n){for(u=r,c=n,t=0;!l&&f&&!o&&t<p.length;t++){var o,i=p[t],d=s.p,b=i[2];r>3?(o=b===n)&&(c=i[(u=i[4])?5:(u=3,3)],i[4]=i[5]=e):i[0]<=d&&((o=r<2&&d<i[1])?(u=0,s.v=n,s.n=i[1]):d<b&&(o=r<3||i[0]>n||n>b)&&(i[4]=r,i[5]=n,s.n=b,u=0))}if(o||r>1)return a;throw l=!0,n}return function(o,p,b){if(f>1)throw TypeError("Generator is already running");for(l&&1===p&&d(p,b),u=p,c=b;(t=u<2?e:c)||!l;){i||(u?u<3?(u>1&&(s.n=-1),d(u,c)):s.n=c:s.v=c);try{if(f=2,i){if(u||(o="next"),t=i[o]){if(!(t=t.call(i,c)))throw TypeError("iterator result is not an object");if(!t.done)return t;c=t.value,u<2&&(u=0)}else 1===u&&(t=i.return)&&t.call(i),u<2&&(c=TypeError("The iterator does not provide a '"+o+"' method"),u=1);i=e}else if((t=(l=s.n<0)?c:r.call(n,s))!==a)break}catch(t){i=e,u=1,c=t}finally{f=1}}return{value:t,done:l}}}(r,o,i),!0),p}var a={};function f(){}function p(){}function l(){}t=Object.getPrototypeOf;var s=[][n]?t(t([][n]())):(c(t={},n,function(){return this}),t),d=l.prototype=f.prototype=Object.create(s);function b(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,l):(e.__proto__=l,c(e,o,"GeneratorFunction")),e.prototype=Object.create(d),e}return p.prototype=l,c(d,"constructor",l),c(l,"constructor",p),p.displayName="GeneratorFunction",c(l,o,"GeneratorFunction"),c(d),c(d,o,"Generator"),c(d,n,function(){return this}),c(d,"toString",function(){return"[object Generator]"}),(u=function(){return{w:i,m:b}})()}function c(e,t,r,n){var o=Object.defineProperty;try{o({},"",{})}catch(e){o=0}c=function(e,t,r,n){function i(t,r){c(e,t,function(e){return this._invoke(t,r,e)})}t?o?o(e,t,{value:r,enumerable:!n,configurable:!n,writable:!n}):e[t]=r:(i("next",0),i("throw",1),i("return",2))},c(e,t,r,n)}function f(e,t,r,n,o,i,a){try{var u=e[i](a),c=u.value}catch(e){return void r(e)}u.done?t(c):Promise.resolve(c).then(n,o)}function p(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,n)}return r}function l(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?p(Object(r),!0).forEach(function(t){s(e,t,r[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):p(Object(r)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})}return e}function s(e,t,r){return(t=function(e){var t=function(e){if("object"!=a(e)||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var r=t.call(e,"string");if("object"!=a(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==a(t)?t:t+""}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function d(){var e,t;return l(l({noKeyItemText:"No features displayed"},arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),{},{id:"menu",load:(e=u().m(function e(){var t;return u().w(function(e){for(;;)switch(e.n){case 0:return e.n=1,o.e(217).then(o.bind(o,77));case 1:return t=e.v.manifest,e.a(2,t)}},e)}),t=function(){var t=this,r=arguments;return new Promise(function(n,o){var i=e.apply(t,r);function a(e){f(i,n,o,a,u,"next",e)}function u(e){f(i,n,o,a,u,"throw",e)}a(void 0)})},function(){return t.apply(this,arguments)})})}return o.d(i,{default:()=>d}),i.default})());
@@ -0,0 +1 @@
1
+ /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
@@ -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
+ }