@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.
Files changed (374) 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/button-definition.md +7 -8
  7. package/docs/api/control-definition.md +17 -1
  8. package/docs/api/panel-definition.md +5 -0
  9. package/docs/api/slots.md +50 -6
  10. package/docs/assets/images/slot-map.svg +61 -262
  11. package/docs/examples/add-polygons.mdx +8 -2
  12. package/docs/examples/add-symbols.mdx +8 -2
  13. package/docs/examples/draw-tools.mdx +3 -3
  14. package/docs/plugins/datasets.md +23 -15
  15. package/docs/plugins/draw.md +79 -16
  16. package/docs/plugins/map-key.md +147 -0
  17. package/docs/plugins/search.md +1 -1
  18. package/docs/plugins.md +5 -1
  19. package/govuk-prototype-kit.config.json +2 -0
  20. package/jest.setup.js +5 -0
  21. package/package.json +9 -1
  22. package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
  23. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
  24. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
  25. package/plugins/beta/draw-ol/dist/esm/im-draw-ol-plugin.js +1 -1
  26. package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -1
  27. package/plugins/beta/map-styles/dist/umd/index.js +1 -1
  28. package/plugins/beta/use-location/dist/esm/im-use-location-plugin.js +1 -1
  29. package/plugins/beta/use-location/dist/umd/im-use-location-plugin.js +1 -1
  30. package/plugins/beta/use-location/src/manifest.js +1 -1
  31. package/plugins/datasets/dist/css/index.css +1 -1
  32. package/plugins/datasets/dist/esm/esriLayerAdapter.js +1 -1
  33. package/plugins/datasets/dist/esm/im-datasets-ml-adapter.js +1 -1
  34. package/plugins/datasets/dist/esm/im-datasets-plugin.js +1 -1
  35. package/plugins/datasets/dist/umd/im-datasets-esri-adapter.js +1 -1
  36. package/plugins/datasets/dist/umd/im-datasets-ml-adapter.js +1 -1
  37. package/plugins/datasets/dist/umd/im-datasets-plugin.js +1 -1
  38. package/plugins/datasets/dist/umd/index.js +1 -1
  39. package/plugins/datasets/src/adapters/esri/esriLayerAdapter.test.js +175 -0
  40. package/plugins/datasets/src/adapters/esri/registry/esriDataset.test.js +55 -0
  41. package/plugins/datasets/src/adapters/loadLayerAdapter.test.js +61 -0
  42. package/plugins/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js +14 -0
  43. package/plugins/datasets/src/api/setOpacity.test.js +9 -0
  44. package/plugins/datasets/src/components/LayersMenu/LayersMenu.jsx +10 -25
  45. package/plugins/datasets/src/components/LayersMenu/LayersMenu.test.jsx +0 -42
  46. package/plugins/datasets/src/datasets.scss +0 -1
  47. package/plugins/datasets/src/fetch/createDynamicSource.js +135 -129
  48. package/plugins/datasets/src/fetch/createDynamicSource.test.js +318 -0
  49. package/plugins/datasets/src/fetch/fetchGeoJSON.test.js +83 -0
  50. package/plugins/datasets/src/index.test.js +36 -0
  51. package/plugins/datasets/src/initialise/DatasetsInit.jsx +17 -7
  52. package/plugins/datasets/src/initialise/DatasetsInit.test.jsx +262 -0
  53. package/plugins/datasets/src/initialise/initialiseDatasets.js +16 -4
  54. package/plugins/datasets/src/initialise/initialiseDatasets.test.js +42 -0
  55. package/plugins/datasets/src/manifest.js +0 -38
  56. package/plugins/datasets/src/manifest.test.js +49 -0
  57. package/plugins/datasets/src/reducers/datasetsToMenu.test.js +54 -1
  58. package/plugins/datasets/src/reducers/pluginState.js +3 -16
  59. package/plugins/datasets/src/reducers/pluginState.test.js +23 -0
  60. package/plugins/datasets/src/registry/dataset.js +13 -1
  61. package/plugins/datasets/src/registry/dataset.test.js +61 -0
  62. package/plugins/datasets/src/registry/datasetRegistry.js +12 -6
  63. package/plugins/datasets/src/registry/datasetRegistry.test.js +16 -4
  64. package/plugins/datasets/src/registry/isVisibleWhen.js +6 -3
  65. package/plugins/datasets/src/registry/isVisibleWhen.test.js +11 -1
  66. package/plugins/datasets/src/utils/bbox.test.js +125 -0
  67. package/plugins/draw/dist/esm/im-draw-ml-adapter.js +1 -1
  68. package/plugins/draw/dist/esm/im-draw-ol-adapter.js +1 -1
  69. package/plugins/draw/dist/esm/im-draw-plugin.js +1 -1
  70. package/plugins/draw/dist/esm/index.js +1 -1
  71. package/plugins/draw/dist/umd/im-draw-ml-adapter.js +2 -1
  72. package/plugins/draw/dist/umd/im-draw-ml-adapter.js.LICENSE.txt +1 -0
  73. package/plugins/draw/dist/umd/im-draw-ol-adapter.js +1 -1
  74. package/plugins/draw/dist/umd/im-draw-plugin.js +1 -1
  75. package/plugins/draw/dist/umd/index.js +1 -1
  76. package/plugins/draw/src/DrawInit.jsx +10 -2
  77. package/plugins/draw/src/DrawInit.test.jsx +51 -10
  78. package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.js +91 -11
  79. package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.test.js +246 -4
  80. package/plugins/draw/src/adapters/maplibre/mapboxDraw.js +109 -14
  81. package/plugins/draw/src/adapters/maplibre/mapboxDraw.test.js +174 -11
  82. package/plugins/draw/src/adapters/maplibre/modes/drawMode/clickHandlers.test.js +12 -0
  83. package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.js +9 -1
  84. package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.test.js +24 -3
  85. package/plugins/draw/src/adapters/maplibre/modes/drawPointMode.js +194 -0
  86. package/plugins/draw/src/adapters/maplibre/modes/drawPointMode.test.js +457 -0
  87. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/__helpers__/harness.js +102 -0
  88. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/keyboardHandlers.js +82 -0
  89. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/keyboardHandlers.test.js +83 -0
  90. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointOperations.js +55 -0
  91. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointOperations.test.js +62 -0
  92. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointerHandlers.js +138 -0
  93. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointerHandlers.test.js +197 -0
  94. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/touchHandlers.js +92 -0
  95. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/touchHandlers.test.js +101 -0
  96. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/undoHandlers.js +46 -0
  97. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/undoHandlers.test.js +42 -0
  98. package/plugins/draw/src/adapters/maplibre/modes/editPointMode.js +151 -0
  99. package/plugins/draw/src/adapters/maplibre/modes/editPointMode.test.js +156 -0
  100. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.js +4 -27
  101. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.test.js +24 -39
  102. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/pointerHandlers.js +4 -5
  103. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.js +20 -23
  104. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.test.js +25 -5
  105. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.js +6 -36
  106. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.test.js +7 -49
  107. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.js +3 -53
  108. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.test.js +8 -33
  109. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.js +29 -72
  110. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.test.js +10 -3
  111. package/plugins/draw/src/adapters/maplibre/pointSymbolImages.js +158 -0
  112. package/plugins/draw/src/adapters/maplibre/pointSymbolImages.test.js +314 -0
  113. package/plugins/draw/src/adapters/maplibre/snap/prototypePatches.js +6 -1
  114. package/plugins/draw/src/adapters/maplibre/snap/prototypePatches.test.js +21 -0
  115. package/plugins/draw/src/adapters/maplibre/snap/snapInstance.js +6 -2
  116. package/plugins/draw/src/adapters/maplibre/snap/snapInstance.test.js +12 -0
  117. package/plugins/draw/src/adapters/maplibre/styles.js +38 -11
  118. package/plugins/draw/src/adapters/maplibre/styles.test.js +39 -0
  119. package/plugins/draw/src/adapters/maplibre/utils/editModeEvents.js +79 -0
  120. package/plugins/draw/src/adapters/maplibre/utils/editModeEvents.test.js +135 -0
  121. package/plugins/draw/src/adapters/maplibre/utils/geometryValidation.js +42 -0
  122. package/plugins/draw/src/adapters/maplibre/utils/geometryValidation.test.js +85 -0
  123. package/plugins/draw/src/adapters/maplibre/utils/keyboardShortcuts.js +34 -0
  124. package/plugins/draw/src/adapters/maplibre/utils/keyboardShortcuts.test.js +78 -0
  125. package/plugins/draw/src/adapters/maplibre/utils/snapHelpers.js +16 -3
  126. package/plugins/draw/src/adapters/maplibre/utils/snapHelpers.test.js +21 -3
  127. package/plugins/draw/src/adapters/maplibre/utils/snapMovement.js +59 -0
  128. package/plugins/draw/src/adapters/maplibre/utils/snapMovement.test.js +73 -0
  129. package/plugins/draw/src/adapters/maplibre/utils/touchDragMath.js +33 -0
  130. package/plugins/draw/src/adapters/maplibre/utils/touchDragMath.test.js +70 -0
  131. package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.js +27 -2
  132. package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.test.js +93 -0
  133. package/plugins/draw/src/adapters/openlayers/__helpers__/harness.js +9 -0
  134. package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.js +19 -1
  135. package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.test.js +34 -1
  136. package/plugins/draw/src/adapters/openlayers/core/styles.js +73 -1
  137. package/plugins/draw/src/adapters/openlayers/core/styles.test.js +122 -3
  138. package/plugins/draw/src/adapters/openlayers/draw/DrawMode.test.js +12 -0
  139. package/plugins/draw/src/adapters/openlayers/draw/drawInput.js +8 -2
  140. package/plugins/draw/src/adapters/openlayers/edit/EditMode.test.js +31 -0
  141. package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.js +9 -5
  142. package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.test.js +33 -0
  143. package/plugins/draw/src/adapters/openlayers/edit/modifyInteraction.js +5 -3
  144. package/plugins/draw/src/adapters/openlayers/edit/modifyInteraction.test.js +11 -0
  145. package/plugins/draw/src/adapters/openlayers/edit/nudge.js +10 -3
  146. package/plugins/draw/src/adapters/openlayers/edit/nudge.test.js +24 -1
  147. package/plugins/draw/src/adapters/openlayers/edit/touchHandler.js +18 -13
  148. package/plugins/draw/src/adapters/openlayers/edit/touchHandler.test.js +46 -1
  149. package/plugins/draw/src/adapters/openlayers/olDraw.js +11 -4
  150. package/plugins/draw/src/adapters/openlayers/olDraw.test.js +48 -6
  151. package/plugins/draw/src/adapters/openlayers/point/drawPointMode.js +156 -0
  152. package/plugins/draw/src/adapters/openlayers/point/drawPointMode.test.js +246 -0
  153. package/plugins/draw/src/adapters/openlayers/point/editPointMode.js +267 -0
  154. package/plugins/draw/src/adapters/openlayers/point/editPointMode.test.js +327 -0
  155. package/plugins/draw/src/adapters/openlayers/point/pointDragInteraction.js +71 -0
  156. package/plugins/draw/src/adapters/openlayers/point/pointOps.js +34 -0
  157. package/plugins/draw/src/adapters/openlayers/point/pointOps.test.js +32 -0
  158. package/plugins/draw/src/adapters/openlayers/point/pointSelectionState.js +82 -0
  159. package/plugins/draw/src/adapters/openlayers/point/pointSelectionState.test.js +107 -0
  160. package/plugins/draw/src/adapters/openlayers/point/pointSymbolImages.js +83 -0
  161. package/plugins/draw/src/adapters/openlayers/point/pointSymbolImages.test.js +214 -0
  162. package/plugins/draw/src/adapters/openlayers/snap/snapIndicator.js +3 -1
  163. package/plugins/draw/src/adapters/openlayers/snap/snapInteraction.js +6 -9
  164. package/plugins/draw/src/adapters/openlayers/snap/snapInteraction.test.js +15 -4
  165. package/plugins/draw/src/adapters/openlayers/utils/olCoords.js +1 -1
  166. package/plugins/draw/src/api/addFeature.js +16 -1
  167. package/plugins/draw/src/api/addFeature.test.js +62 -5
  168. package/plugins/draw/src/api/createNewShape.js +41 -0
  169. package/plugins/draw/src/api/createNewShape.test.js +63 -0
  170. package/plugins/draw/src/api/editFeature.js +7 -4
  171. package/plugins/draw/src/api/editFeature.test.js +16 -0
  172. package/plugins/draw/src/api/newLine.js +2 -40
  173. package/plugins/draw/src/api/newPoint.js +42 -0
  174. package/plugins/draw/src/api/newPoint.test.js +117 -0
  175. package/plugins/draw/src/api/newPolygon.js +2 -40
  176. package/plugins/draw/src/api/setStyle.js +43 -0
  177. package/plugins/draw/src/api/setStyle.test.js +75 -0
  178. package/plugins/draw/src/events.js +17 -10
  179. package/plugins/draw/src/events.test.js +14 -0
  180. package/plugins/draw/src/manifest.js +18 -6
  181. package/plugins/draw/src/manifest.test.js +32 -1
  182. package/plugins/draw/src/reducer.test.js +7 -0
  183. package/plugins/draw/src/utils/stripInternalProperties.js +19 -0
  184. package/plugins/draw/src/utils/stripInternalProperties.test.js +50 -0
  185. package/plugins/draw/src/utils/symbolKeys.js +5 -0
  186. package/plugins/draw/src/validation/liveDrawChecks.test.js +54 -0
  187. package/plugins/draw/src/validation/liveStroke.test.js +64 -1
  188. package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
  189. package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
  190. package/plugins/interact/dist/umd/index.js +1 -1
  191. package/plugins/interact/src/hooks/useHighlightSync.js +33 -12
  192. package/plugins/interact/src/hooks/useHighlightSync.test.js +96 -25
  193. package/plugins/interact/src/manifest.js +1 -1
  194. package/plugins/interact/src/utils/featureQueries.js +18 -0
  195. package/plugins/interact/src/utils/featureQueries.test.js +15 -0
  196. package/plugins/interact/src/utils/spatial.js +9 -3
  197. package/plugins/interact/src/utils/spatial.test.js +12 -1
  198. package/plugins/map-key/dist/css/index.css +68 -0
  199. package/plugins/map-key/dist/esm/im-map-key-plugin.js +1 -0
  200. package/plugins/map-key/dist/esm/index.js +1 -0
  201. package/plugins/map-key/dist/umd/im-map-key-plugin.js +2 -0
  202. package/plugins/map-key/dist/umd/im-map-key-plugin.js.LICENSE.txt +1 -0
  203. package/plugins/map-key/dist/umd/index.js +2 -0
  204. package/plugins/map-key/dist/umd/index.js.LICENSE.txt +1 -0
  205. package/plugins/map-key/package.json +28 -0
  206. package/plugins/map-key/src/components/Key/EmptyKey.jsx +7 -0
  207. package/plugins/{datasets → map-key}/src/components/Key/EmptyKey.test.jsx +2 -2
  208. package/plugins/map-key/src/components/Key/Key.jsx +43 -0
  209. package/plugins/{datasets → map-key}/src/components/Key/Key.module.scss +21 -14
  210. package/plugins/map-key/src/components/Key/Key.test.jsx +73 -0
  211. package/plugins/map-key/src/components/Key/KeyGroupItem.jsx +16 -0
  212. package/plugins/map-key/src/components/Key/KeyGroupItem.test.jsx +53 -0
  213. package/plugins/map-key/src/components/Key/KeyItem.jsx +26 -0
  214. package/plugins/map-key/src/components/Key/KeyItem.test.jsx +67 -0
  215. package/plugins/map-key/src/components/Key/KeySvg.jsx +41 -0
  216. package/plugins/{datasets → map-key}/src/components/Key/KeySvg.test.jsx +14 -12
  217. package/plugins/map-key/src/components/Key/KeySvgLine.jsx +22 -0
  218. package/plugins/{datasets → map-key}/src/components/Key/KeySvgLine.test.jsx +1 -1
  219. package/plugins/{datasets → map-key}/src/components/Key/KeySvgPattern.jsx +7 -2
  220. package/plugins/{datasets → map-key}/src/components/Key/KeySvgPattern.test.jsx +8 -2
  221. package/plugins/map-key/src/components/Key/KeySvgRect.jsx +26 -0
  222. package/plugins/{datasets → map-key}/src/components/Key/KeySvgRect.test.jsx +1 -1
  223. package/plugins/{datasets → map-key}/src/components/Key/KeySvgSymbol.jsx +8 -3
  224. package/plugins/{datasets → map-key}/src/components/Key/KeySvgSymbol.test.jsx +17 -6
  225. package/plugins/map-key/src/components/Key/MapKey.jsx +53 -0
  226. package/plugins/map-key/src/components/Key/MapKey.test.jsx +147 -0
  227. package/plugins/{datasets → map-key}/src/components/Key/svgProperties.js +2 -2
  228. package/plugins/{datasets → map-key}/src/components/Key/svgProperties.test.js +2 -2
  229. package/plugins/map-key/src/index.js +13 -0
  230. package/plugins/map-key/src/index.test.js +31 -0
  231. package/plugins/map-key/src/initialise/MapKeyInit.jsx +15 -0
  232. package/plugins/map-key/src/initialise/MapKeyInit.test.jsx +39 -0
  233. package/plugins/map-key/src/manifest.js +30 -0
  234. package/plugins/map-key/src/manifest.test.js +63 -0
  235. package/plugins/map-key/src/mapKey.scss +4 -0
  236. package/plugins/map-key/src/registry/getDatasetRegistry.js +6 -0
  237. package/plugins/map-key/src/registry/getDatasetRegistry.test.js +23 -0
  238. package/plugins/map-key/src/registry/index.js +3 -0
  239. package/plugins/map-key/src/registry/index.test.js +15 -0
  240. package/plugins/menu/dist/css/index.css +80 -0
  241. package/plugins/menu/dist/esm/im-menu-plugin.js +1 -0
  242. package/plugins/menu/dist/esm/index.js +1 -0
  243. package/plugins/menu/dist/umd/im-menu-plugin.js +1 -0
  244. package/plugins/menu/dist/umd/index.js +2 -0
  245. package/plugins/menu/dist/umd/index.js.LICENSE.txt +1 -0
  246. package/plugins/menu/package.json +28 -0
  247. package/plugins/menu/src/components/Menu/CheckboxGroupWrapper.jsx +21 -0
  248. package/plugins/menu/src/components/Menu/GroupLegend.jsx +17 -0
  249. package/plugins/menu/src/components/Menu/GroupLegend.test.jsx +68 -0
  250. package/plugins/menu/src/components/Menu/Menu.jsx +19 -0
  251. package/plugins/menu/src/components/Menu/Menu.module.scss +90 -0
  252. package/plugins/menu/src/components/Menu/Menu.test.jsx +161 -0
  253. package/plugins/menu/src/components/Menu/MenuCheckbox.jsx +35 -0
  254. package/plugins/menu/src/components/Menu/MenuCheckbox.test.jsx +93 -0
  255. package/plugins/menu/src/components/Menu/MenuGroup.jsx +11 -0
  256. package/plugins/{datasets/src/components/LayersMenu/LayersMenuRadio.jsx → menu/src/components/Menu/MenuRadio.jsx} +6 -4
  257. package/plugins/{datasets/src/components/LayersMenu/LayersMenuRadio.test.jsx → menu/src/components/Menu/MenuRadio.test.jsx} +18 -18
  258. package/plugins/menu/src/components/Menu/RadioGroupWrapper.jsx +32 -0
  259. package/plugins/{datasets/src/components/LayersMenu/LayersRadioGroupWrapper.test.jsx → menu/src/components/Menu/RadioGroupWrapper.test.jsx} +21 -21
  260. package/plugins/menu/src/components/Menu/useIdPrefix.jsx +4 -0
  261. package/plugins/menu/src/index.js +13 -0
  262. package/plugins/menu/src/index.test.js +31 -0
  263. package/plugins/menu/src/initialise/MenuInit.jsx +24 -0
  264. package/plugins/menu/src/initialise/MenuInit.test.jsx +50 -0
  265. package/plugins/menu/src/initialise/createMenu.js +10 -0
  266. package/plugins/menu/src/initialise/createMenu.test.js +37 -0
  267. package/plugins/menu/src/manifest.js +35 -0
  268. package/plugins/menu/src/manifest.test.js +63 -0
  269. package/plugins/menu/src/menu.scss +4 -0
  270. package/plugins/menu/src/reducers/menuStateReducer.test.js +38 -0
  271. package/plugins/menu/src/reducers/pluginState.js +35 -0
  272. package/plugins/menu/src/reducers/pluginState.test.js +57 -0
  273. package/plugins/menu/src/registry/getDatasetRegistry.js +9 -0
  274. package/plugins/menu/src/registry/getDatasetRegistry.test.js +23 -0
  275. package/plugins/menu/src/registry/index.js +3 -0
  276. package/plugins/menu/src/registry/index.test.js +15 -0
  277. package/plugins/menu/src/registry/isVisibleWhen.js +43 -0
  278. package/plugins/menu/src/registry/isVisibleWhen.test.js +48 -0
  279. package/plugins/search/dist/css/index.css +1 -1
  280. package/plugins/search/dist/esm/im-search-plugin.js +1 -1
  281. package/plugins/search/dist/esm/index.js +1 -1
  282. package/plugins/search/dist/umd/im-search-plugin.js +1 -1
  283. package/plugins/search/dist/umd/index.js +1 -1
  284. package/plugins/search/src/Search.jsx +2 -3
  285. package/plugins/search/src/components/Form/Form.module.scss +9 -20
  286. package/plugins/search/src/index.js +0 -1
  287. package/plugins/search/src/index.test.js +2 -4
  288. package/plugins/search/src/manifest.js +1 -1
  289. package/plugins/search/src/search.scss +17 -16
  290. package/providers/beta/openlayers/dist/esm/im-openlayers-provider.js +1 -1
  291. package/providers/beta/openlayers/dist/umd/im-openlayers-provider.js +1 -1
  292. package/providers/beta/openlayers/dist/umd/index.js +1 -1
  293. package/providers/beta/openlayers/src/openlayersProvider.js +4 -1
  294. package/providers/beta/openlayers/src/openlayersProvider.test.js +18 -0
  295. package/providers/beta/openlayers/src/utils/highlightFeatures.js +52 -5
  296. package/providers/beta/openlayers/src/utils/highlightFeatures.test.js +176 -0
  297. package/providers/beta/openlayers/src/utils/symbolImages.js +40 -0
  298. package/providers/beta/openlayers/src/utils/symbolImages.test.js +58 -0
  299. package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
  300. package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
  301. package/providers/maplibre/dist/umd/index.js +1 -1
  302. package/providers/maplibre/src/utils/drawLayerBuckets.js +14 -0
  303. package/providers/maplibre/src/utils/drawLayerBuckets.test.js +18 -0
  304. package/providers/maplibre/src/utils/highlightFeatures.js +80 -55
  305. package/providers/maplibre/src/utils/highlightFeatures.test.js +156 -17
  306. package/providers/maplibre/src/utils/hoverCursor.js +30 -14
  307. package/providers/maplibre/src/utils/hoverCursor.test.js +35 -0
  308. package/providers/maplibre/src/utils/patternImages.js +1 -1
  309. package/providers/maplibre/src/utils/symbolImages.js +41 -3
  310. package/providers/maplibre/src/utils/symbolImages.test.js +40 -6
  311. package/rollup.esm.mjs +11 -1
  312. package/src/App/components/Actions/Actions.test.jsx +47 -0
  313. package/src/App/components/Hints/Hints.test.jsx +13 -0
  314. package/src/App/components/KeyboardHelp/KeyboardHelp.jsx +25 -23
  315. package/src/App/components/KeyboardHelp/KeyboardHelp.test.jsx +22 -5
  316. package/src/App/components/MoveControls/MoveControls.module.scss +41 -10
  317. package/src/App/components/Panel/Panel.jsx +65 -8
  318. package/src/App/components/Panel/Panel.module.scss +49 -15
  319. package/src/App/components/Panel/Panel.test.jsx +114 -1
  320. package/src/App/components/Tabs/Tabs.jsx +43 -17
  321. package/src/App/components/Tabs/Tabs.module.scss +32 -5
  322. package/src/App/components/Tabs/Tabs.test.jsx +40 -10
  323. package/src/App/components/Tooltip/Tooltip.test.jsx +12 -14
  324. package/src/App/hooks/useFeatureItems.js +16 -7
  325. package/src/App/hooks/useFeatureItems.test.js +57 -0
  326. package/src/App/hooks/useLayoutMeasurements.js +95 -84
  327. package/src/App/hooks/useLayoutMeasurements.test.js +61 -1
  328. package/src/App/layout/Layout.jsx +9 -10
  329. package/src/App/layout/Layout.test.jsx +2 -0
  330. package/src/App/layout/layout.module.scss +31 -17
  331. package/src/App/registry/pluginRegistry.js +1 -1
  332. package/src/App/registry/pluginRegistry.test.js +12 -0
  333. package/src/App/renderer/HtmlElementHost.jsx +18 -5
  334. package/src/App/renderer/HtmlElementHost.test.jsx +54 -0
  335. package/src/App/renderer/groupByKey.js +28 -0
  336. package/src/App/renderer/groupByKey.test.js +39 -0
  337. package/src/App/renderer/groupIntoTabs.js +42 -0
  338. package/src/App/renderer/groupIntoTabs.test.js +95 -0
  339. package/src/App/renderer/mapButtons.js +97 -129
  340. package/src/App/renderer/mapButtons.test.js +67 -83
  341. package/src/App/renderer/mapControls.js +4 -1
  342. package/src/App/renderer/mapControls.test.js +32 -0
  343. package/src/App/renderer/mapPanels.js +53 -11
  344. package/src/App/renderer/mapPanels.test.js +95 -2
  345. package/src/App/renderer/orderItems.js +28 -0
  346. package/src/App/renderer/orderItems.test.js +50 -0
  347. package/src/App/renderer/slotAggregator.js +2 -18
  348. package/src/App/renderer/slotHelpers.js +3 -1
  349. package/src/App/renderer/slotHelpers.test.js +5 -0
  350. package/src/App/renderer/slots.js +3 -0
  351. package/src/App/store/AppProvider.jsx +1 -0
  352. package/src/App/store/appDispatchMiddleware.js +1 -1
  353. package/src/App/store/appDispatchMiddleware.test.js +8 -0
  354. package/src/config/appConfig.js +2 -2
  355. package/src/config/events.js +2 -0
  356. package/src/scss/settings/_colors.scss +1 -0
  357. package/src/scss/settings/_dimensions.scss +2 -3
  358. package/src/scss/settings/_transition.scss +1 -1
  359. package/src/services/eventBus.js +44 -0
  360. package/src/services/eventBus.test.js +83 -0
  361. package/src/services/symbolRegistry.js +1 -1
  362. package/src/types.js +31 -3
  363. package/webpack.umd.mjs +2 -0
  364. package/plugins/datasets/src/components/Key/EmptyKey.jsx +0 -7
  365. package/plugins/datasets/src/components/Key/Key.jsx +0 -50
  366. package/plugins/datasets/src/components/Key/KeyGroupItem.jsx +0 -18
  367. package/plugins/datasets/src/components/Key/KeyItem.jsx +0 -23
  368. package/plugins/datasets/src/components/Key/KeySvg.jsx +0 -22
  369. package/plugins/datasets/src/components/Key/KeySvgLine.jsx +0 -19
  370. package/plugins/datasets/src/components/Key/KeySvgRect.jsx +0 -22
  371. package/plugins/datasets/src/components/LayersMenu/LayersRadioGroupWrapper.jsx +0 -41
  372. /package/plugins/{datasets → menu}/src/reducers/menuStateReducer.js +0 -0
  373. /package/{providers/maplibre/src → src}/utils/rasteriseToImageData.js +0 -0
  374. /package/{providers/maplibre/src → src}/utils/rasteriseToImageData.test.js +0 -0
@@ -15,6 +15,7 @@ Use the datasets plugin to overlay GeoJSON polygon data on your map. This exampl
15
15
  import InteractiveMap from '@defra/interactive-map'
16
16
  import maplibreProvider from '@defra/interactive-map/providers/maplibre'
17
17
  import createDatasetsPlugin from '@defra/interactive-map/plugins/datasets'
18
+ import createMapKeyPlugin from '@defra/interactive-map/plugins/map-key'
18
19
 
19
20
  // GeoJSON can also be loaded from a URL; use the tiles property for vector tile sources
20
21
  const geojson = {
@@ -100,6 +101,8 @@ Use the datasets plugin to overlay GeoJSON polygon data on your map. This exampl
100
101
  }]
101
102
  })
102
103
 
104
+ const mapKeyPlugin = createMapKeyPlugin()
105
+
103
106
  new InteractiveMap('my-map', {
104
107
  behaviour: 'inline',
105
108
  mapProvider: maplibreProvider(),
@@ -110,7 +113,7 @@ Use the datasets plugin to overlay GeoJSON polygon data on your map. This exampl
110
113
  center: [-2.464, 54.558],
111
114
  zoom: 14,
112
115
  containerHeight: '516px',
113
- plugins: [datasetsPlugin]
116
+ plugins: [datasetsPlugin, mapKeyPlugin]
114
117
  })
115
118
  `
116
119
  },
@@ -121,6 +124,7 @@ Use the datasets plugin to overlay GeoJSON polygon data on your map. This exampl
121
124
  <script src="/your-assets-path/interactive-map/index.js"></script>
122
125
  <script src="/your-assets-path/maplibre-provider/index.js"></script>
123
126
  <script src="/your-assets-path/datasets-plugin/index.js"></script>
127
+ <script src="/your-assets-path/map-key-plugin/index.js"></script>
124
128
 
125
129
  <script>
126
130
  // GeoJSON can also be loaded from a URL; use the tiles property for vector tile sources
@@ -207,6 +211,8 @@ Use the datasets plugin to overlay GeoJSON polygon data on your map. This exampl
207
211
  }]
208
212
  })
209
213
 
214
+ const mapKeyPlugin = defra.mapKeyPlugin()
215
+
210
216
  new defra.InteractiveMap('my-map', {
211
217
  behaviour: 'inline',
212
218
  mapProvider: defra.maplibreProvider(),
@@ -217,7 +223,7 @@ Use the datasets plugin to overlay GeoJSON polygon data on your map. This exampl
217
223
  center: [-2.464, 54.558],
218
224
  zoom: 14,
219
225
  containerHeight: '516px',
220
- plugins: [datasetsPlugin]
226
+ plugins: [datasetsPlugin, mapKeyPlugin]
221
227
  })
222
228
  </script>
223
229
  `
@@ -15,6 +15,7 @@ Use the datasets plugin to overlay GeoJSON data on your map. Each dataset can co
15
15
  import InteractiveMap from '@defra/interactive-map'
16
16
  import maplibreProvider from '@defra/interactive-map/providers/maplibre'
17
17
  import createDatasetsPlugin from '@defra/interactive-map/plugins/datasets'
18
+ import createMapKeyPlugin from '@defra/interactive-map/plugins/map-key'
18
19
 
19
20
  const symbolGraphic = 'M3 15H1V1h2v2h2V1h2v5h2V4h2v2h2V4h2v11H6V9H3v6z'
20
21
 
@@ -76,6 +77,8 @@ Use the datasets plugin to overlay GeoJSON data on your map. Each dataset can co
76
77
  }]
77
78
  })
78
79
 
80
+ const mapKeyPlugin = createMapKeyPlugin()
81
+
79
82
  new InteractiveMap('my-map', {
80
83
  behaviour: 'inline',
81
84
  mapProvider: maplibreProvider(),
@@ -86,7 +89,7 @@ Use the datasets plugin to overlay GeoJSON data on your map. Each dataset can co
86
89
  center: [-2.4608, 54.5574],
87
90
  zoom: 14,
88
91
  containerHeight: '516px',
89
- plugins: [datasetsPlugin]
92
+ plugins: [datasetsPlugin, mapKeyPlugin]
90
93
  })
91
94
  `
92
95
  },
@@ -97,6 +100,7 @@ Use the datasets plugin to overlay GeoJSON data on your map. Each dataset can co
97
100
  <script src="/your-assets-path/interactive-map/index.js"></script>
98
101
  <script src="/your-assets-path/maplibre-provider/index.js"></script>
99
102
  <script src="/your-assets-path/datasets-plugin/index.js"></script>
103
+ <script src="/your-assets-path/map-key-plugin/index.js"></script>
100
104
 
101
105
  <script>
102
106
  const symbolGraphic = 'M3 15H1V1h2v2h2V1h2v5h2V4h2v2h2V4h2v11H6V9H3v6z'
@@ -159,6 +163,8 @@ Use the datasets plugin to overlay GeoJSON data on your map. Each dataset can co
159
163
  }]
160
164
  })
161
165
 
166
+ const mapKeyPlugin = defra.mapKeyPlugin()
167
+
162
168
  new defra.InteractiveMap('my-map', {
163
169
  behaviour: 'inline',
164
170
  mapProvider: defra.maplibreProvider(),
@@ -169,7 +175,7 @@ Use the datasets plugin to overlay GeoJSON data on your map. Each dataset can co
169
175
  center: [-2.4608, 54.5574],
170
176
  zoom: 14,
171
177
  containerHeight: '516px',
172
- plugins: [datasetsPlugin]
178
+ plugins: [datasetsPlugin, mapKeyPlugin]
173
179
  })
174
180
  </script>
175
181
  `
@@ -19,7 +19,7 @@ This example configures snapping (`snapLayers`) against the base map style's woo
19
19
  import InteractiveMap from '@defra/interactive-map'
20
20
  import maplibreProvider from '@defra/interactive-map/providers/maplibre'
21
21
  import createInteractPlugin from '@defra/interactive-map/plugins/interact'
22
- import createDrawPlugin from '@defra/interactive-map/plugins/draw-ml'
22
+ import createDrawPlugin from '@defra/interactive-map/plugins/draw'
23
23
 
24
24
  const DRAW_LAYERS = ['fill-inactive.cold', 'stroke-inactive.cold']
25
25
 
@@ -149,7 +149,7 @@ This example configures snapping (`snapLayers`) against the base map style's woo
149
149
  <script src="/your-assets-path/interactive-map/index.js"></script>
150
150
  <script src="/your-assets-path/maplibre-provider/index.js"></script>
151
151
  <script src="/your-assets-path/interact-plugin/index.js"></script>
152
- <script src="/your-assets-path/draw-ml-plugin/index.js"></script>
152
+ <script src="/your-assets-path/draw-plugin/index.js"></script>
153
153
 
154
154
  <script>
155
155
  const DRAW_LAYERS = ['fill-inactive.cold', 'stroke-inactive.cold']
@@ -165,7 +165,7 @@ This example configures snapping (`snapLayers`) against the base map style's woo
165
165
  })
166
166
 
167
167
  // Snap new vertices to the woodland layer when drawing near one
168
- const drawPlugin = defra.drawMLPlugin({
168
+ const drawPlugin = defra.drawPlugin({
169
169
  snapLayers: ['OS/Woodland:3/Local/1']
170
170
  })
171
171
 
@@ -1,6 +1,9 @@
1
1
  # Datasets Plugin
2
2
 
3
- The datasets plugin renders GeoJSON and vector tile datasets on the map, with support for polygon, line, and symbol (point) layer types, sublayer style rules, layer visibility toggling, a key panel, and runtime style and data updates.
3
+ The datasets plugin renders GeoJSON and vector tile datasets on the map, with support for polygon, line, and symbol (point) layer types, sublayer style rules, layer visibility toggling, and runtime style and data updates.
4
+
5
+ > [!IMPORTANT]
6
+ > **Upgrading?** This plugin no longer renders key of symbols itself — that button and panel have been removed. Add the [Map Key](./map-key.md) plugin to restore it. Your `showInKey` config is unaffected and needs no changes.
4
7
 
5
8
  ## ESM usage
6
9
 
@@ -282,6 +285,9 @@ Initial visibility of the dataset.
282
285
 
283
286
  When `true`, the dataset appears in the Key panel with its style symbol and label. Sublayers inherit this value — set `showInKey: false` on an individual sublayer to opt it out.
284
287
 
288
+ > [!NOTE]
289
+ > Rendering the Key panel requires the [Map Key](./map-key.md) plugin to be added alongside this one — `showInKey` has no visible effect on its own.
290
+
285
291
  ---
286
292
 
287
293
  ### `showInMenu`
@@ -303,9 +309,7 @@ Groups this dataset with others sharing the same `groupLabel` in the LayersMenu
303
309
 
304
310
  ### `keySymbolShape`
305
311
 
306
- **Type:** `'polygon' | 'line'`
307
-
308
- Overrides the shape used to render the key symbol for this dataset. Defaults to a polygon shape.
312
+ Set within [`style`](#style) not a top-level dataset property. See [Map Key: `keySymbolShape`](./map-key.md#keysymbolshape).
309
313
 
310
314
  ---
311
315
 
@@ -340,21 +344,25 @@ Visual style for the dataset. All style properties must be nested within this ob
340
344
 
341
345
  Setting `symbol` or `symbolSvgContent` renders the dataset as a point layer instead of a polygon/line layer.
342
346
 
343
- | Property | Type | Description |
344
- |----------|------|-------------|
345
- | `symbol` | `string` | Registered symbol ID e.g. `'pin'`, `'circle'`, `'square'` |
346
- | `symbolSvgContent` | `string` | Inline SVG content for a fully custom symbol (no `<svg>` wrapper). Takes precedence over `symbol` |
347
- | `symbolViewBox` | `string` | SVG viewBox for the symbol e.g. `'0 0 38 38'`. Defaults to the registered symbol's viewBox |
348
- | `symbolAnchor` | `[number, number]` | Anchor point as a normalised `[x, y]` pair. Defaults to the registered symbol's anchor |
349
- | `symbolBackgroundColor` | `string \| Record<string, string>` | Background fill colour of the symbol |
350
- | `symbolForegroundColor` | `string \| Record<string, string>` | Foreground fill colour of the symbol (e.g. the inner dot) |
351
- | `symbolHaloWidth` | `string` | Stroke width of the halo in SVG units |
352
- | `symbolGraphic` | `string` | SVG `d` attribute for the foreground graphic path. Use named values (`'dot'`, `'cross'`, `'diamond'`, `'triangle'`, `'square'`) or supply your own path data |
347
+ Each is documented in full in [Symbol Config](../api/symbol-config.md), under a `symbol` prefix here to distinguish them from the polygon/line properties in the same style object:
353
348
 
354
- Symbol colour properties use the `symbol` prefix to distinguish them from polygon/line properties in the same style object. They follow the same resolution order and support style-keyed colour objects in the same way as markers — see [Symbol Config](../api/symbol-config.md) for details.
349
+ | Property | Symbol Config property |
350
+ |----------|-------------------------|
351
+ | `symbol` | [`symbol`](../api/symbol-config.md#symbol) |
352
+ | `symbolSvgContent` | [`symbolSvgContent`](../api/symbol-config.md#symbolsvgcontent) |
353
+ | `symbolViewBox` | [`viewBox`](../api/symbol-config.md#viewbox) |
354
+ | `symbolAnchor` | [`anchor`](../api/symbol-config.md#anchor) |
355
+ | `symbolBackgroundColor` | [`backgroundColor`](../api/symbol-config.md#backgroundcolor) |
356
+ | `symbolForegroundColor` | [`foregroundColor`](../api/symbol-config.md#foregroundcolor) |
357
+ | `symbolHaloWidth` | Stroke width of the halo in SVG units. Not currently documented in Symbol Config |
358
+ | `symbolGraphic` | [`graphic`](../api/symbol-config.md#graphic) |
359
+
360
+ They follow the same resolution order and support style-keyed colour objects in the same way as markers.
355
361
 
356
362
  `haloColor` and `selectedColor` are not settable here — they are basemap-level properties set on [`MapStyleConfig`](../api/map-style-config.md).
357
363
 
364
+ `symbolDescription` and `keySymbolShape` only affect how an entry looks in the Key panel — see [Map Key: Key display properties](./map-key.md#key-display-properties) for details.
365
+
358
366
  ```js
359
367
  // Polygon/line dataset
360
368
  style: {
@@ -1,6 +1,6 @@
1
1
  # Draw Plugin
2
2
 
3
- The draw plugin lets users draw and edit polygon and line features on the map — placing vertices by click, tap, or keyboard, snapping to existing map layers, and validating geometry as it's built. Polygons can also be split and merged. It works identically with both the MapLibre and OpenLayers map providers, determining the correct adapter to use from the `mapProvider` passed to `InteractiveMap` — there's nothing to configure.
3
+ The draw plugin lets users draw and edit point, polygon and line features on the map — placing vertices by click, tap, or keyboard, snapping to existing map layers, and validating geometry as it's built. Polygons can also be split and merged. It works identically with both the MapLibre and OpenLayers map providers, determining the correct adapter to use from the `mapProvider` passed to `InteractiveMap` — there's nothing to configure.
4
4
 
5
5
  ## ESM usage
6
6
 
@@ -54,7 +54,7 @@ Options are passed to the factory function when creating the plugin.
54
54
 
55
55
  **Type:** `string[]`
56
56
 
57
- Vector tile source-layer names to snap new and edited vertices against. Can be overridden per call — see `newPolygon`, `newLine`, `editFeature`, and `split` below.
57
+ Vector tile source-layer names to snap new and edited vertices against. Can be overridden per call — see `newPolygon`, `newLine`, `newPoint`, `editFeature`, and `split` below.
58
58
 
59
59
  The layer names available depend entirely on your basemap style — there's no universal default, so check your style's vector tile source(s) for the source-layer names to use. The example below (`'OS/TopographicArea_1/Agricultural Land'`) is specific to an Ordnance Survey basemap style.
60
60
 
@@ -72,7 +72,7 @@ createDrawPlugin({
72
72
 
73
73
  **Type:** `Function`
74
74
 
75
- Plugin-level validation callback, called throughout the draw/edit lifecycle so you can enforce your own rules (e.g. "shapes must stay inside a boundary") alongside the built-in ones. Can be overridden per call — see [Validation](#validation) below for the full contract, and `newPolygon`, `newLine`, `editFeature` for the per-call override.
75
+ Plugin-level validation callback, called throughout the draw/edit lifecycle so you can enforce your own rules (e.g. "shapes must stay inside a boundary") alongside the built-in ones. Can be overridden per call — see [Validation](#validation) below for the full contract, and `newPolygon`, `newLine`, `newPoint`, `editFeature` for the per-call override.
76
76
 
77
77
  ---
78
78
 
@@ -141,7 +141,7 @@ Rule failures gate the Done button (the shape can pass through interim invalid s
141
141
 
142
142
  ### `onGeometryChange` callback
143
143
 
144
- Set at the plugin level (`createDrawPlugin({ onGeometryChange })`) or per call (`newPolygon`/`newLine`/`editFeature`'s `options.onGeometryChange`, which takes precedence when given). Not used by `split` (which validates that the line actually bisects the shape) or `merge`/`addFeature` (no validation).
144
+ Set at the plugin level (`createDrawPlugin({ onGeometryChange })`) or per call (`newPolygon`/`newLine`/`newPoint`/`editFeature`'s `options.onGeometryChange`, which takes precedence when given). Not used by `split` (which validates that the line actually bisects the shape) or `merge`/`addFeature`/`setStyle` (no validation). For a `Point`, only the `'place'` phase applies — placing or dragging a point can be vetoed, but there's no minimum-vertices/self-intersection/area check.
145
145
 
146
146
  **Signature:** `onGeometryChange(event) => boolean | { valid: boolean, reason?: string } | undefined`
147
147
 
@@ -157,7 +157,7 @@ Set at the plugin level (`createDrawPlugin({ onGeometryChange })`) or per call (
157
157
  |----------|------|-------------|
158
158
  | `feature` | `GeoJSON.Feature` | The shape at this point — the in-progress feature during `'preview'`, the committed/candidate feature at every other phase |
159
159
  | `phase` | `string` | See table below |
160
- | `mode` | `'draw_polygon' \| 'draw_line' \| 'edit_vertex'` | The active draw mode |
160
+ | `mode` | `'draw_polygon' \| 'draw_line' \| 'draw_point' \| 'edit_vertex' \| 'edit_point'` | The active draw mode |
161
161
  | `vertexIndex` | `number` | Index of the vertex being placed/added/moved/inserted/deleted. Present on `'place'` and every `'commit-*'` phase |
162
162
  | `numVertices` | `number` | Count of already-committed vertices, excluding any in-progress cursor point. Present on every `'preview'` call |
163
163
 
@@ -185,7 +185,7 @@ createDrawPlugin({
185
185
 
186
186
  ## Methods
187
187
 
188
- Methods are called on the plugin instance. `newPolygon`, `newLine`, `editFeature`, `addFeature`, `deleteFeature`, `split`, and `merge` all need `mapProvider.draw` to be ready — call them after [`draw:ready`](#drawready).
188
+ Methods are called on the plugin instance. `newPolygon`, `newLine`, `newPoint`, `editFeature`, `addFeature`, `setStyle`, `deleteFeature`, `split`, and `merge` all need `mapProvider.draw` to be ready — call them after [`draw:ready`](#drawready).
189
189
 
190
190
  ---
191
191
 
@@ -225,9 +225,39 @@ drawPlugin.newLine(crypto.randomUUID(), {
225
225
 
226
226
  ---
227
227
 
228
+ ### `newPoint(featureId, options?)`
229
+
230
+ Start drawing a new point. Unlike `newPolygon`/`newLine`, it commits as soon as a point is placed — there's no Done step.
231
+
232
+ | Argument | Type | Description |
233
+ |----------|------|-------------|
234
+ | `featureId` | `string` | **Required.** ID to assign the finished feature |
235
+ | `options.snapLayers` | `string[]` | Overrides the plugin-level `snapLayers` for this session |
236
+ | `options.onGeometryChange` | `Function` | Overrides the plugin-level `onGeometryChange` for this session — see [Validation](#validation) |
237
+ | `options.properties` | `Object` | Custom GeoJSON properties to set on the finished feature |
238
+ | `options.symbol` | `string` | Built-in symbol id — `'pin'`, `'circle'`, or `'square'` |
239
+ | `options.symbolSvgContent` | `string` | Custom SVG markup, used instead of `symbol` |
240
+ | `options.symbolBackgroundColor` | `string \| Record<string, string>` | Symbol background colour |
241
+ | `options.symbolForegroundColor` | `string \| Record<string, string>` | Symbol foreground colour |
242
+ | `options.symbolGraphic` | `string` | Overrides the symbol's inner graphic (built-in name or SVG path data) |
243
+ | `options.symbolHaloWidth` | `number` | Symbol halo width |
244
+ | `options.symbolViewBox` | `string` | SVG `viewBox`, for use with `symbolSvgContent` |
245
+ | `options.symbolAnchor` | `[number, number]` | Normalised `[x, y]` anchor point |
246
+
247
+ These mirror [MarkerOptions](../api/marker-config.md#markeroptions)' `symbol`-family properties (prefixed with `symbol` here to sit alongside other feature properties) — see [Symbol Config](../api/symbol-config.md) for the full resolution order and SVG token structure. Points with no symbol config render with the plugin's default marker.
248
+
249
+ ```js
250
+ drawPlugin.newPoint(crypto.randomUUID(), {
251
+ symbol: 'pin',
252
+ symbolBackgroundColor: { outdoor: '#d4351c', dark: '#ff6b6b' }
253
+ })
254
+ ```
255
+
256
+ ---
257
+
228
258
  ### `editFeature(featureId, options?)`
229
259
 
230
- Open an existing feature in vertex-edit mode. Returns `false` (without doing anything) if the feature doesn't exist or the plugin isn't ready yet — check the return value before assuming the edit session started.
260
+ Open an existing feature in edit mode — vertex-edit for a `Polygon`/`LineString`, single-coordinate drag for a `Point`. Returns `false` (without doing anything) if the feature doesn't exist or the plugin isn't ready yet — check the return value before assuming the edit session started.
231
261
 
232
262
  | Argument | Type | Description |
233
263
  |----------|------|-------------|
@@ -246,16 +276,19 @@ if (!editSuccess) {
246
276
 
247
277
  ### `addFeature(feature)`
248
278
 
249
- Add a feature directly to the map without a draw session — e.g. loading in existing shapes on `draw:ready`.
279
+ Add a `Point`, `LineString`, or `Polygon` feature directly to the map without a draw session — e.g. loading in existing shapes on `draw:ready`.
250
280
 
251
281
  | Argument | Type | Description |
252
282
  |----------|------|-------------|
253
283
  | `feature.id` | `string` | **Required.** Feature ID |
254
- | `feature.geometry` | `GeoJSON.Geometry` | **Required.** `Polygon` or `LineString` geometry |
255
- | `feature.stroke` | `string \| Record<string, string>` | Stroke colour |
256
- | `feature.fill` | `string \| Record<string, string>` | Fill colour |
257
- | `feature.strokeWidth` | `number` | Stroke width in pixels |
258
- | `feature.properties` | `Object` | Custom GeoJSON properties |
284
+ | `feature.type` | `string` | Defaults to `'Feature'` if omitted |
285
+ | `feature.geometry` | `GeoJSON.Geometry` | **Required.** `Point`, `LineString`, or `Polygon` geometry |
286
+ | `feature.stroke` | `string \| Record<string, string>` | Stroke colour (`LineString`/`Polygon`) |
287
+ | `feature.fill` | `string \| Record<string, string>` | Fill colour (`Polygon`) |
288
+ | `feature.strokeWidth` | `number` | Stroke width in pixels (`LineString`/`Polygon`) |
289
+ | `feature.properties` | `Object` | Custom GeoJSON properties — a `Point`'s `symbol`-family properties go here (see `newPoint` above) |
290
+
291
+ A feature with a missing/unsupported `geometry.type` or no `geometry.coordinates` is logged as a warning and ignored.
259
292
 
260
293
  ```js
261
294
  interactiveMap.on('draw:ready', () => {
@@ -267,11 +300,33 @@ interactiveMap.on('draw:ready', () => {
267
300
  fill: 'rgba(0,112,60,0.2)',
268
301
  strokeWidth: 2
269
302
  })
303
+
304
+ drawPlugin.addFeature({
305
+ id: 'monument1',
306
+ type: 'Feature',
307
+ geometry: { type: 'Point', coordinates: [-2.878, 54.709] },
308
+ properties: { symbol: 'square', symbolBackgroundColor: '#28a197' }
309
+ })
270
310
  })
271
311
  ```
272
312
 
273
313
  ---
274
314
 
315
+ ### `setStyle(featureId, styleChanges)`
316
+
317
+ Update an existing feature's style — stroke/fill/strokeWidth or, for a `Point`, its `symbol`-family properties (see `newPoint` above). Only the keys you pass are changed; anything else the feature already has is left alone. Returns `false` if the feature doesn't exist.
318
+
319
+ | Argument | Type | Description |
320
+ |----------|------|-------------|
321
+ | `featureId` | `string` | **Required.** ID of the feature to update |
322
+ | `styleChanges` | `Object` | **Required.** Any mix of `stroke`, `fill`, `strokeWidth`, or `symbol`-family properties |
323
+
324
+ ```js
325
+ drawPlugin.setStyle('monument1', { symbolBackgroundColor: { outdoor: '#1d70b8', dark: '#4c9ed9' } })
326
+ ```
327
+
328
+ ---
329
+
275
330
  ### `deleteFeature(featureIds)`
276
331
 
277
332
  Remove one or more features from the map.
@@ -371,9 +426,9 @@ Emitted once the draw plugin has initialised. Safe to call API methods from here
371
426
 
372
427
  ### `draw:started`
373
428
 
374
- Emitted when `newPolygon` or `newLine` starts a new draw session.
429
+ Emitted when `newPolygon`, `newLine`, or `newPoint` starts a new draw session.
375
430
 
376
- **Payload:** `{ mode: 'draw_polygon' | 'draw_line' }`
431
+ **Payload:** `{ mode: 'draw_polygon' | 'draw_line' | 'draw_point' }`
377
432
 
378
433
  ---
379
434
 
@@ -381,7 +436,7 @@ Emitted when `newPolygon` or `newLine` starts a new draw session.
381
436
 
382
437
  Emitted when `editFeature` opens an existing feature for editing.
383
438
 
384
- **Payload:** `{ mode: 'edit_polygon' | 'edit_line' }`
439
+ **Payload:** `{ mode: 'edit_polygon' | 'edit_line' | 'edit_point' }`
385
440
 
386
441
  ---
387
442
 
@@ -457,6 +512,14 @@ Emitted after `deleteFeature` removes a feature.
457
512
 
458
513
  ---
459
514
 
515
+ ### `draw:stylechange`
516
+
517
+ Emitted after `setStyle` updates a feature's style.
518
+
519
+ **Payload:** `{ featureId: string, properties: Object }` — the flattened style/symbol properties that were applied
520
+
521
+ ---
522
+
460
523
  ### `draw:split`
461
524
 
462
525
  Emitted when `split` computes a successful split.
@@ -0,0 +1,147 @@
1
+ # Map Key Plugin
2
+
3
+ Renders a key of symbols present on the map, in a key panel.
4
+
5
+ Today, the [Datasets](./datasets.md) plugin is wired up to it via a dedicated hook — datasets and sublayers configured with `showInKey: true` feed their styled symbols into the key panel automatically. Other plugins may hook into the key panel in future, but that isn't built yet; Datasets is currently the only integration.
6
+
7
+ The plugin holds no dataset-specific config itself — when paired with the Datasets plugin, it reads dataset styling from that plugin's registry at runtime via that hook. There's nothing to configure to make that connection; both plugins just need to be present in `plugins`.
8
+
9
+ > [!NOTE]
10
+ > Buttons render in the shared `top-left` slot in the order their plugins appear in the `plugins` array — list `datasetsPlugin` before `mapKeyPlugin` to get Layers before Key.
11
+
12
+ ## ESM usage
13
+
14
+ ```js
15
+ import createDatasetsPlugin from '@defra/interactive-map/plugins/datasets'
16
+ import createMapKeyPlugin from '@defra/interactive-map/plugins/map-key'
17
+
18
+ const datasetsPlugin = createDatasetsPlugin({
19
+ datasets: [
20
+ {
21
+ id: 'my-parcels',
22
+ label: 'My parcels',
23
+ geojson: 'https://example.com/api/parcels',
24
+ showInKey: true,
25
+ showInMenu: true,
26
+ style: {
27
+ stroke: '#d4351c',
28
+ strokeWidth: 2,
29
+ fill: 'transparent'
30
+ }
31
+ }
32
+ ]
33
+ })
34
+
35
+ const mapKeyPlugin = createMapKeyPlugin()
36
+
37
+ const interactiveMap = new InteractiveMap({
38
+ plugins: [datasetsPlugin, mapKeyPlugin]
39
+ })
40
+ ```
41
+
42
+ ## UMD usage
43
+
44
+ Copy the entire `plugins/map-key/dist/umd/` directory to `/your-assets-path/plugins/map-key/umd/`. The plugin uses dynamic imports, so all files in the directory must be served from the same location. Then add the script tag alongside the Datasets plugin's:
45
+
46
+ ```html
47
+ <script defer src="/your-assets-path/plugins/datasets/umd/index.js"></script>
48
+ <script defer src="/your-assets-path/plugins/map-key/umd/index.js"></script>
49
+ ```
50
+
51
+ ```js
52
+ const datasetsPlugin = defra.datasetsPlugin({
53
+ datasets: [
54
+ {
55
+ id: 'my-parcels',
56
+ label: 'My parcels',
57
+ geojson: 'https://example.com/api/parcels',
58
+ showInKey: true,
59
+ showInMenu: true,
60
+ style: {
61
+ stroke: '#d4351c',
62
+ strokeWidth: 2,
63
+ fill: 'transparent'
64
+ }
65
+ }
66
+ ]
67
+ })
68
+
69
+ const mapKeyPlugin = defra.mapKeyPlugin()
70
+
71
+ const interactiveMap = new defra.InteractiveMap('map', {
72
+ mapProvider: defra.maplibreProvider(),
73
+ plugins: [datasetsPlugin, mapKeyPlugin]
74
+ })
75
+ ```
76
+
77
+ > [!NOTE]
78
+ > **GOV.UK Prototype Kit** — skip the copy step. All files are served automatically. Use this path instead:
79
+ > ```html
80
+ > <script defer src="/plugin-assets/%40defra%2Finteractive-map/plugins/map-key/dist/umd/index.js"></script>
81
+ > ```
82
+
83
+ ## Options
84
+
85
+ Options are passed to the factory function when creating the plugin.
86
+
87
+ ---
88
+
89
+ ### `noKeyItemText`
90
+
91
+ **Type:** `string`
92
+ **Default:** `'No features displayed'`
93
+
94
+ Text shown in the key panel when it has no visible entries to display — for example, no datasets or sublayers configured with `showInKey: true` currently have visible features on the map.
95
+
96
+ ```js
97
+ createMapKeyPlugin({ noKeyItemText: 'No layers to show' })
98
+ ```
99
+
100
+ ---
101
+
102
+ ### `includeModes`
103
+
104
+ **Type:** `string[]`
105
+
106
+ When set, the plugin only initialises when the app is in one of the specified modes.
107
+
108
+ ---
109
+
110
+ ### `excludeModes`
111
+
112
+ **Type:** `string[]`
113
+
114
+ When set, the plugin does not initialise when the app is in one of the specified modes.
115
+
116
+ ---
117
+
118
+ ## Key display properties
119
+
120
+ These properties control how an entry looks in the key panel — they have no effect on how a feature renders on the map itself. Today the only way to set them is via a dataset's [`style`](./datasets.md#style) object, since Datasets is the only plugin feeding this key panel.
121
+
122
+ ---
123
+
124
+ ### `keySymbolShape`
125
+
126
+ **Type:** `'polygon' | 'line'`
127
+ **Default:** `'polygon'`
128
+
129
+ Overrides the shape used to render a polygon/line entry's symbol in the key.
130
+
131
+ ---
132
+
133
+ ### `symbolDescription`
134
+
135
+ **Type:** `string | Record<string, string>`
136
+
137
+ Accessible description of the symbol shown alongside its key entry.
138
+
139
+ ---
140
+
141
+ ## Methods
142
+
143
+ This plugin does not expose any public methods.
144
+
145
+ ## Events
146
+
147
+ This plugin does not emit any custom events.
@@ -136,7 +136,7 @@ searchPlugin({
136
136
 
137
137
  Controls whether the search input is always visible or hidden behind an open button.
138
138
 
139
- - **Mobile** — by default the search is hidden and requires a button tap to open. When `expanded: true`, it moves to the banner slot and is shown inline at the top of the map at all times.
139
+ - **Mobile** — the search form always lives in the `header` slot, above the top row. By default it's collapsed behind a button tap; setting `expanded: true` shows it inline at all times and removes the open button.
140
140
  - **Tablet and desktop** — the search always sits in the `top-left` slot regardless of this setting, but setting `expanded: true` removes the open button so the input is immediately visible without interaction.
141
141
 
142
142
  ---
package/docs/plugins.md CHANGED
@@ -30,7 +30,11 @@ The following plugins are in early development. APIs and features may change.
30
30
 
31
31
  ### [Datasets](./plugins/datasets.md)
32
32
 
33
- Add datasets to your map, configure the display, layer toggling and render a key of symbology.
33
+ Render GeoJSON and vector tile datasets on the map, with a menu for toggling layer visibility. Pair with the [Map Key](./plugins/map-key.md) plugin to render a key of symbols.
34
+
35
+ ### [Map Key](./plugins/map-key.md)
36
+
37
+ Renders a key of symbols in a panel. Currently sourced from the Datasets plugin.
34
38
 
35
39
  ### [Draw](./plugins/draw.md)
36
40
 
@@ -66,6 +66,8 @@
66
66
  "/plugins/draw/dist",
67
67
  "/providers/beta/open-names/dist",
68
68
  "/plugins/datasets/dist",
69
+ "/plugins/map-key/dist",
70
+ "/plugins/menu/dist",
69
71
  "/plugins/beta/map-styles/dist",
70
72
  "/plugins/beta/scale-bar/dist",
71
73
  "/plugins/beta/use-location/dist",
package/jest.setup.js CHANGED
@@ -1,5 +1,10 @@
1
1
  import '@testing-library/jest-dom'
2
2
 
3
+ // structuredClone is not exposed by jsdom; polyfill it using JSON round-trip
4
+ if (typeof structuredClone === 'undefined') {
5
+ global.structuredClone = (obj) => JSON.parse(JSON.stringify(obj))
6
+ }
7
+
3
8
  // Global mock for window.matchMedia
4
9
  if (!window.matchMedia) {
5
10
  Object.defineProperty(window, 'matchMedia', {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra/interactive-map",
3
- "version": "0.0.40-alpha",
3
+ "version": "0.0.42-alpha",
4
4
  "description": "An accessible map component",
5
5
  "repository": {
6
6
  "type": "git",
@@ -47,6 +47,12 @@
47
47
  "./plugins/datasets": {
48
48
  "import": "./plugins/datasets/dist/esm/index.js"
49
49
  },
50
+ "./plugins/menu": {
51
+ "import": "./plugins/menu/dist/esm/index.js"
52
+ },
53
+ "./plugins/map-key": {
54
+ "import": "./plugins/map-key/dist/esm/index.js"
55
+ },
50
56
  "./plugins/datasets/adapters/maplibre": {
51
57
  "import": "./plugins/datasets/dist/adapters/maplibre/esm/index.js"
52
58
  },
@@ -69,6 +75,8 @@
69
75
  "./plugins/draw-ml/css": "./plugins/beta/draw-ml/dist/css/index.css",
70
76
  "./plugins/scale-bar/css": "./plugins/beta/scale-bar/dist/css/index.css",
71
77
  "./plugins/datasets/css": "./plugins/datasets/dist/css/index.css",
78
+ "./plugins/menu/css": "./plugins/menu/dist/css/index.css",
79
+ "./plugins/map-key/css": "./plugins/map-key/dist/css/index.css",
72
80
  "./plugins/frame/css": "./plugins/beta/frame/dist/css/index.css",
73
81
  "./plugins/map-styles/css": "./plugins/beta/map-styles/dist/css/index.css",
74
82
  "./plugins/search/css": "./plugins/search/dist/css/index.css",