@defra/interactive-map 0.0.39-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 (387) 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/api.md +4 -4
  9. package/docs/assets/images/slot-map.svg +61 -262
  10. package/docs/examples/draw-tools.mdx +3 -3
  11. package/docs/plugins/draw.md +80 -17
  12. package/docs/plugins/search.md +1 -1
  13. package/govuk-prototype-kit.config.json +2 -0
  14. package/jest.setup.js +5 -0
  15. package/package.json +9 -1
  16. package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
  17. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
  18. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
  19. package/plugins/beta/draw-ol/dist/esm/im-draw-ol-plugin.js +1 -1
  20. package/plugins/beta/map-styles/dist/esm/im-map-styles-plugin.js +1 -1
  21. package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -1
  22. package/plugins/beta/map-styles/dist/umd/index.js +1 -1
  23. package/plugins/datasets/dist/css/index.css +1 -1
  24. package/plugins/datasets/dist/esm/esriLayerAdapter.js +1 -1
  25. package/plugins/datasets/dist/esm/im-datasets-ml-adapter.js +1 -1
  26. package/plugins/datasets/dist/esm/im-datasets-plugin.js +1 -1
  27. package/plugins/datasets/dist/umd/im-datasets-esri-adapter.js +1 -1
  28. package/plugins/datasets/dist/umd/im-datasets-ml-adapter.js +1 -1
  29. package/plugins/datasets/dist/umd/im-datasets-plugin.js +1 -1
  30. package/plugins/datasets/dist/umd/index.js +1 -1
  31. package/plugins/datasets/src/adapters/esri/esriLayerAdapter.js +2 -3
  32. package/plugins/datasets/src/adapters/esri/esriLayerAdapter.test.js +175 -0
  33. package/plugins/datasets/src/adapters/esri/registry/esriDataset.js +1 -1
  34. package/plugins/datasets/src/adapters/esri/registry/esriDataset.test.js +55 -0
  35. package/plugins/datasets/src/adapters/loadLayerAdapter.js +1 -1
  36. package/plugins/datasets/src/adapters/loadLayerAdapter.test.js +61 -0
  37. package/plugins/datasets/src/adapters/maplibre/maplibreLayerAdapter.js +1 -3
  38. package/plugins/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js +17 -3
  39. package/plugins/datasets/src/api/setOpacity.test.js +9 -0
  40. package/plugins/datasets/src/components/LayersMenu/LayersMenu.jsx +10 -25
  41. package/plugins/datasets/src/components/LayersMenu/LayersMenu.test.jsx +0 -42
  42. package/plugins/datasets/src/datasets.scss +0 -1
  43. package/plugins/datasets/src/fetch/createDynamicSource.js +135 -129
  44. package/plugins/datasets/src/fetch/createDynamicSource.test.js +318 -0
  45. package/plugins/datasets/src/fetch/fetchGeoJSON.test.js +83 -0
  46. package/plugins/datasets/src/index.test.js +36 -0
  47. package/plugins/datasets/src/initialise/DatasetsInit.jsx +17 -7
  48. package/plugins/datasets/src/initialise/DatasetsInit.test.jsx +262 -0
  49. package/plugins/datasets/src/initialise/initialiseDatasets.js +16 -5
  50. package/plugins/datasets/src/initialise/initialiseDatasets.test.js +42 -0
  51. package/plugins/datasets/src/manifest.js +0 -38
  52. package/plugins/datasets/src/manifest.test.js +49 -0
  53. package/plugins/datasets/src/reducers/datasetsToMenu.test.js +54 -1
  54. package/plugins/datasets/src/reducers/pluginState.js +3 -16
  55. package/plugins/datasets/src/reducers/pluginState.test.js +23 -0
  56. package/plugins/datasets/src/registry/dataset.js +15 -4
  57. package/plugins/datasets/src/registry/dataset.test.js +61 -0
  58. package/plugins/datasets/src/registry/datasetRegistry.js +12 -9
  59. package/plugins/datasets/src/registry/datasetRegistry.test.js +17 -5
  60. package/plugins/datasets/src/registry/globalDataset.js +0 -3
  61. package/plugins/datasets/src/registry/isVisibleWhen.js +6 -3
  62. package/plugins/datasets/src/registry/isVisibleWhen.test.js +11 -1
  63. package/plugins/datasets/src/utils/bbox.test.js +125 -0
  64. package/plugins/draw/dist/esm/im-draw-ml-adapter.js +1 -1
  65. package/plugins/draw/dist/esm/im-draw-ol-adapter.js +1 -1
  66. package/plugins/draw/dist/esm/im-draw-plugin.js +1 -1
  67. package/plugins/draw/dist/esm/index.js +1 -1
  68. package/plugins/draw/dist/umd/im-draw-ml-adapter.js +2 -1
  69. package/plugins/draw/dist/umd/im-draw-ml-adapter.js.LICENSE.txt +1 -0
  70. package/plugins/draw/dist/umd/im-draw-ol-adapter.js +1 -1
  71. package/plugins/draw/dist/umd/im-draw-plugin.js +1 -1
  72. package/plugins/draw/dist/umd/index.js +1 -1
  73. package/plugins/draw/src/DrawInit.jsx +12 -4
  74. package/plugins/draw/src/DrawInit.test.jsx +51 -10
  75. package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.js +92 -12
  76. package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.test.js +246 -4
  77. package/plugins/draw/src/adapters/maplibre/mapboxDraw.js +109 -14
  78. package/plugins/draw/src/adapters/maplibre/mapboxDraw.test.js +174 -11
  79. package/plugins/draw/src/adapters/maplibre/modes/drawMode/clickHandlers.test.js +12 -0
  80. package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.js +9 -1
  81. package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.test.js +24 -3
  82. package/plugins/draw/src/adapters/maplibre/modes/drawMode/pointerHandlers.js +1 -1
  83. package/plugins/draw/src/adapters/maplibre/modes/drawMode/pointerHandlers.test.js +1 -1
  84. package/plugins/draw/src/adapters/maplibre/modes/drawPointMode.js +194 -0
  85. package/plugins/draw/src/adapters/maplibre/modes/drawPointMode.test.js +457 -0
  86. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/__helpers__/harness.js +102 -0
  87. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/keyboardHandlers.js +82 -0
  88. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/keyboardHandlers.test.js +83 -0
  89. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointOperations.js +55 -0
  90. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointOperations.test.js +62 -0
  91. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointerHandlers.js +138 -0
  92. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointerHandlers.test.js +197 -0
  93. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/touchHandlers.js +92 -0
  94. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/touchHandlers.test.js +101 -0
  95. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/undoHandlers.js +46 -0
  96. package/plugins/draw/src/adapters/maplibre/modes/editPointMode/undoHandlers.test.js +42 -0
  97. package/plugins/draw/src/adapters/maplibre/modes/editPointMode.js +151 -0
  98. package/plugins/draw/src/adapters/maplibre/modes/editPointMode.test.js +156 -0
  99. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.js +5 -28
  100. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.test.js +24 -39
  101. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/pointerHandlers.js +4 -5
  102. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.js +20 -23
  103. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.test.js +25 -5
  104. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.js +6 -36
  105. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.test.js +7 -49
  106. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.js +4 -54
  107. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.test.js +8 -33
  108. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.js +29 -72
  109. package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.test.js +11 -4
  110. package/plugins/draw/src/adapters/maplibre/pointSymbolImages.js +158 -0
  111. package/plugins/draw/src/adapters/maplibre/pointSymbolImages.test.js +314 -0
  112. package/plugins/draw/src/adapters/maplibre/snap/prototypePatches.js +6 -1
  113. package/plugins/draw/src/adapters/maplibre/snap/prototypePatches.test.js +21 -0
  114. package/plugins/draw/src/adapters/maplibre/snap/snapInstance.js +6 -2
  115. package/plugins/draw/src/adapters/maplibre/snap/snapInstance.test.js +12 -0
  116. package/plugins/draw/src/adapters/maplibre/styles.js +38 -11
  117. package/plugins/draw/src/adapters/maplibre/styles.test.js +39 -0
  118. package/plugins/draw/src/adapters/maplibre/utils/editModeEvents.js +79 -0
  119. package/plugins/draw/src/adapters/maplibre/utils/editModeEvents.test.js +135 -0
  120. package/plugins/draw/src/adapters/maplibre/utils/geometryValidation.js +42 -0
  121. package/plugins/draw/src/adapters/maplibre/utils/geometryValidation.test.js +85 -0
  122. package/plugins/draw/src/adapters/maplibre/utils/keyboardShortcuts.js +34 -0
  123. package/plugins/draw/src/adapters/maplibre/utils/keyboardShortcuts.test.js +78 -0
  124. package/plugins/draw/src/adapters/maplibre/utils/snapHelpers.js +16 -3
  125. package/plugins/draw/src/adapters/maplibre/utils/snapHelpers.test.js +21 -3
  126. package/plugins/draw/src/adapters/maplibre/utils/snapMovement.js +59 -0
  127. package/plugins/draw/src/adapters/maplibre/utils/snapMovement.test.js +73 -0
  128. package/plugins/draw/src/adapters/maplibre/utils/touchDragMath.js +33 -0
  129. package/plugins/draw/src/adapters/maplibre/utils/touchDragMath.test.js +70 -0
  130. package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.js +27 -2
  131. package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.test.js +93 -0
  132. package/plugins/draw/src/adapters/openlayers/__helpers__/harness.js +9 -0
  133. package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.js +19 -1
  134. package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.test.js +34 -1
  135. package/plugins/draw/src/adapters/openlayers/core/styles.js +73 -1
  136. package/plugins/draw/src/adapters/openlayers/core/styles.test.js +122 -3
  137. package/plugins/draw/src/adapters/openlayers/draw/DrawMode.js +1 -0
  138. package/plugins/draw/src/adapters/openlayers/draw/DrawMode.test.js +27 -1
  139. package/plugins/draw/src/adapters/openlayers/draw/drawInput.js +24 -4
  140. package/plugins/draw/src/adapters/openlayers/draw/drawInput.test.js +47 -3
  141. package/plugins/draw/src/adapters/openlayers/edit/EditMode.js +1 -1
  142. package/plugins/draw/src/adapters/openlayers/edit/EditMode.test.js +32 -1
  143. package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.js +9 -5
  144. package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.test.js +34 -1
  145. package/plugins/draw/src/adapters/openlayers/edit/modifyInteraction.js +5 -3
  146. package/plugins/draw/src/adapters/openlayers/edit/modifyInteraction.test.js +11 -0
  147. package/plugins/draw/src/adapters/openlayers/edit/nudge.js +12 -5
  148. package/plugins/draw/src/adapters/openlayers/edit/nudge.test.js +26 -3
  149. package/plugins/draw/src/adapters/openlayers/edit/touchHandler.js +18 -13
  150. package/plugins/draw/src/adapters/openlayers/edit/touchHandler.test.js +46 -1
  151. package/plugins/draw/src/adapters/openlayers/olDraw.js +11 -4
  152. package/plugins/draw/src/adapters/openlayers/olDraw.test.js +48 -6
  153. package/plugins/draw/src/adapters/openlayers/point/drawPointMode.js +156 -0
  154. package/plugins/draw/src/adapters/openlayers/point/drawPointMode.test.js +246 -0
  155. package/plugins/draw/src/adapters/openlayers/point/editPointMode.js +267 -0
  156. package/plugins/draw/src/adapters/openlayers/point/editPointMode.test.js +327 -0
  157. package/plugins/draw/src/adapters/openlayers/point/pointDragInteraction.js +71 -0
  158. package/plugins/draw/src/adapters/openlayers/point/pointOps.js +34 -0
  159. package/plugins/draw/src/adapters/openlayers/point/pointOps.test.js +32 -0
  160. package/plugins/draw/src/adapters/openlayers/point/pointSelectionState.js +82 -0
  161. package/plugins/draw/src/adapters/openlayers/point/pointSelectionState.test.js +107 -0
  162. package/plugins/draw/src/adapters/openlayers/point/pointSymbolImages.js +83 -0
  163. package/plugins/draw/src/adapters/openlayers/point/pointSymbolImages.test.js +214 -0
  164. package/plugins/draw/src/adapters/openlayers/snap/snapIndicator.js +3 -1
  165. package/plugins/draw/src/adapters/openlayers/snap/snapInteraction.js +6 -9
  166. package/plugins/draw/src/adapters/openlayers/snap/snapInteraction.test.js +15 -4
  167. package/plugins/draw/src/adapters/openlayers/utils/olCoords.js +1 -1
  168. package/plugins/draw/src/api/addFeature.js +16 -1
  169. package/plugins/draw/src/api/addFeature.test.js +62 -5
  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/newPoint.js +42 -0
  173. package/plugins/draw/src/api/newPoint.test.js +117 -0
  174. package/plugins/draw/src/api/setStyle.js +43 -0
  175. package/plugins/draw/src/api/setStyle.test.js +75 -0
  176. package/plugins/draw/src/events.js +21 -14
  177. package/plugins/draw/src/events.test.js +15 -1
  178. package/plugins/draw/src/manifest.js +18 -6
  179. package/plugins/draw/src/manifest.test.js +32 -1
  180. package/plugins/draw/src/reducer.test.js +7 -0
  181. package/plugins/draw/src/utils/stripInternalProperties.js +19 -0
  182. package/plugins/draw/src/utils/stripInternalProperties.test.js +50 -0
  183. package/plugins/draw/src/utils/symbolKeys.js +5 -0
  184. package/plugins/draw/src/validation/liveDrawChecks.test.js +54 -0
  185. package/plugins/draw/src/validation/liveStroke.test.js +64 -1
  186. package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
  187. package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
  188. package/plugins/interact/dist/umd/index.js +1 -1
  189. package/plugins/interact/src/hooks/useCrossHairVisibility.js +12 -4
  190. package/plugins/interact/src/hooks/useCrossHairVisibility.test.js +88 -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/utils/featureQueries.js +18 -0
  194. package/plugins/interact/src/utils/featureQueries.test.js +15 -0
  195. package/plugins/interact/src/utils/spatial.js +9 -3
  196. package/plugins/interact/src/utils/spatial.test.js +12 -1
  197. package/plugins/map-key/dist/css/index.css +62 -0
  198. package/plugins/map-key/dist/esm/im-map-key-plugin.js +1 -0
  199. package/plugins/map-key/dist/esm/index.js +1 -0
  200. package/plugins/map-key/dist/umd/im-map-key-plugin.js +2 -0
  201. package/plugins/map-key/dist/umd/im-map-key-plugin.js.LICENSE.txt +1 -0
  202. package/plugins/map-key/dist/umd/index.js +2 -0
  203. package/plugins/map-key/dist/umd/index.js.LICENSE.txt +1 -0
  204. package/plugins/map-key/package.json +28 -0
  205. package/plugins/map-key/src/components/Key/EmptyKey.jsx +7 -0
  206. package/plugins/{datasets → map-key}/src/components/Key/EmptyKey.test.jsx +2 -2
  207. package/plugins/map-key/src/components/Key/Key.jsx +41 -0
  208. package/plugins/{datasets → map-key}/src/components/Key/Key.module.scss +15 -14
  209. package/plugins/map-key/src/components/Key/Key.test.jsx +73 -0
  210. package/plugins/map-key/src/components/Key/KeyGroupItem.jsx +16 -0
  211. package/plugins/map-key/src/components/Key/KeyGroupItem.test.jsx +53 -0
  212. package/plugins/map-key/src/components/Key/KeyItem.jsx +29 -0
  213. package/plugins/map-key/src/components/Key/KeyItem.test.jsx +67 -0
  214. package/plugins/map-key/src/components/Key/KeySvg.jsx +42 -0
  215. package/plugins/{datasets → map-key}/src/components/Key/KeySvg.test.jsx +14 -12
  216. package/plugins/map-key/src/components/Key/KeySvgLine.jsx +28 -0
  217. package/plugins/{datasets → map-key}/src/components/Key/KeySvgLine.test.jsx +1 -1
  218. package/plugins/map-key/src/components/Key/KeySvgPattern.jsx +23 -0
  219. package/plugins/{datasets → map-key}/src/components/Key/KeySvgPattern.test.jsx +2 -2
  220. package/plugins/map-key/src/components/Key/KeySvgRect.jsx +33 -0
  221. package/plugins/{datasets → map-key}/src/components/Key/KeySvgRect.test.jsx +1 -1
  222. package/plugins/map-key/src/components/Key/KeySvgSymbol.jsx +27 -0
  223. package/plugins/{datasets → map-key}/src/components/Key/KeySvgSymbol.test.jsx +5 -6
  224. package/plugins/map-key/src/components/Key/MapKey.jsx +50 -0
  225. package/plugins/map-key/src/components/Key/MapKey.test.jsx +130 -0
  226. package/plugins/{datasets → map-key}/src/components/Key/svgProperties.js +2 -2
  227. package/plugins/{datasets → map-key}/src/components/Key/svgProperties.test.js +2 -2
  228. package/plugins/map-key/src/index.js +13 -0
  229. package/plugins/map-key/src/index.test.js +31 -0
  230. package/plugins/map-key/src/initialise/MapKeyInit.jsx +15 -0
  231. package/plugins/map-key/src/initialise/MapKeyInit.test.jsx +39 -0
  232. package/plugins/map-key/src/manifest.js +30 -0
  233. package/plugins/map-key/src/manifest.test.js +63 -0
  234. package/plugins/map-key/src/mapKey.scss +4 -0
  235. package/plugins/map-key/src/registry/getDatasetRegistry.js +6 -0
  236. package/plugins/map-key/src/registry/getDatasetRegistry.test.js +23 -0
  237. package/plugins/map-key/src/registry/index.js +3 -0
  238. package/plugins/map-key/src/registry/index.test.js +15 -0
  239. package/plugins/menu/dist/css/index.css +80 -0
  240. package/plugins/menu/dist/esm/im-menu-plugin.js +1 -0
  241. package/plugins/menu/dist/esm/index.js +1 -0
  242. package/plugins/menu/dist/umd/im-menu-plugin.js +1 -0
  243. package/plugins/menu/dist/umd/index.js +2 -0
  244. package/plugins/menu/dist/umd/index.js.LICENSE.txt +1 -0
  245. package/plugins/menu/package.json +28 -0
  246. package/plugins/menu/src/components/Menu/CheckboxGroupWrapper.jsx +21 -0
  247. package/plugins/menu/src/components/Menu/GroupLegend.jsx +17 -0
  248. package/plugins/menu/src/components/Menu/GroupLegend.test.jsx +68 -0
  249. package/plugins/menu/src/components/Menu/Menu.jsx +19 -0
  250. package/plugins/menu/src/components/Menu/Menu.module.scss +90 -0
  251. package/plugins/menu/src/components/Menu/Menu.test.jsx +161 -0
  252. package/plugins/menu/src/components/Menu/MenuCheckbox.jsx +35 -0
  253. package/plugins/menu/src/components/Menu/MenuCheckbox.test.jsx +93 -0
  254. package/plugins/menu/src/components/Menu/MenuGroup.jsx +11 -0
  255. package/plugins/{datasets/src/components/LayersMenu/LayersMenuRadio.jsx → menu/src/components/Menu/MenuRadio.jsx} +6 -4
  256. package/plugins/{datasets/src/components/LayersMenu/LayersMenuRadio.test.jsx → menu/src/components/Menu/MenuRadio.test.jsx} +18 -18
  257. package/plugins/menu/src/components/Menu/RadioGroupWrapper.jsx +32 -0
  258. package/plugins/{datasets/src/components/LayersMenu/LayersRadioGroupWrapper.test.jsx → menu/src/components/Menu/RadioGroupWrapper.test.jsx} +21 -21
  259. package/plugins/menu/src/components/Menu/useIdPrefix.jsx +4 -0
  260. package/plugins/menu/src/index.js +13 -0
  261. package/plugins/menu/src/index.test.js +31 -0
  262. package/plugins/menu/src/initialise/MenuInit.jsx +24 -0
  263. package/plugins/menu/src/initialise/MenuInit.test.jsx +50 -0
  264. package/plugins/menu/src/initialise/createMenu.js +10 -0
  265. package/plugins/menu/src/initialise/createMenu.test.js +37 -0
  266. package/plugins/menu/src/manifest.js +35 -0
  267. package/plugins/menu/src/manifest.test.js +63 -0
  268. package/plugins/menu/src/menu.scss +4 -0
  269. package/plugins/menu/src/reducers/menuStateReducer.test.js +38 -0
  270. package/plugins/menu/src/reducers/pluginState.js +35 -0
  271. package/plugins/menu/src/reducers/pluginState.test.js +57 -0
  272. package/plugins/menu/src/registry/getDatasetRegistry.js +9 -0
  273. package/plugins/menu/src/registry/getDatasetRegistry.test.js +23 -0
  274. package/plugins/menu/src/registry/index.js +3 -0
  275. package/plugins/menu/src/registry/index.test.js +15 -0
  276. package/plugins/menu/src/registry/isVisibleWhen.js +43 -0
  277. package/plugins/menu/src/registry/isVisibleWhen.test.js +48 -0
  278. package/plugins/search/dist/css/index.css +1 -1
  279. package/plugins/search/dist/esm/im-search-plugin.js +1 -1
  280. package/plugins/search/dist/esm/index.js +1 -1
  281. package/plugins/search/dist/umd/im-search-plugin.js +1 -1
  282. package/plugins/search/dist/umd/index.js +1 -1
  283. package/plugins/search/src/Search.jsx +7 -5
  284. package/plugins/search/src/components/Form/Form.module.scss +9 -20
  285. package/plugins/search/src/index.js +0 -1
  286. package/plugins/search/src/index.test.js +2 -4
  287. package/plugins/search/src/manifest.js +1 -1
  288. package/plugins/search/src/search.scss +17 -16
  289. package/providers/beta/openlayers/dist/esm/im-openlayers-provider.js +1 -1
  290. package/providers/beta/openlayers/dist/umd/im-openlayers-provider.js +1 -1
  291. package/providers/beta/openlayers/dist/umd/index.js +1 -1
  292. package/providers/beta/openlayers/src/openlayersProvider.js +4 -1
  293. package/providers/beta/openlayers/src/openlayersProvider.test.js +18 -0
  294. package/providers/beta/openlayers/src/utils/highlightFeatures.js +52 -5
  295. package/providers/beta/openlayers/src/utils/highlightFeatures.test.js +176 -0
  296. package/providers/beta/openlayers/src/utils/symbolImages.js +40 -0
  297. package/providers/beta/openlayers/src/utils/symbolImages.test.js +58 -0
  298. package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
  299. package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
  300. package/providers/maplibre/dist/umd/index.js +1 -1
  301. package/providers/maplibre/src/utils/drawLayerBuckets.js +14 -0
  302. package/providers/maplibre/src/utils/drawLayerBuckets.test.js +18 -0
  303. package/providers/maplibre/src/utils/highlightFeatures.js +80 -55
  304. package/providers/maplibre/src/utils/highlightFeatures.test.js +156 -17
  305. package/providers/maplibre/src/utils/hoverCursor.js +30 -14
  306. package/providers/maplibre/src/utils/hoverCursor.test.js +35 -0
  307. package/providers/maplibre/src/utils/patternImages.js +1 -1
  308. package/providers/maplibre/src/utils/symbolImages.js +41 -3
  309. package/providers/maplibre/src/utils/symbolImages.test.js +40 -6
  310. package/rollup.esm.mjs +11 -1
  311. package/sonar-project.properties +7 -1
  312. package/src/App/components/Actions/Actions.test.jsx +47 -0
  313. package/src/App/components/Attributions/Attributions.module.scss +10 -0
  314. package/src/App/components/Hints/Hints.jsx +7 -2
  315. package/src/App/components/Hints/Hints.test.jsx +13 -0
  316. package/src/App/components/KeyboardHelp/KeyboardHelp.jsx +2 -3
  317. package/src/App/components/KeyboardHelp/KeyboardHelp.test.jsx +3 -6
  318. package/src/App/components/{MoveControl/MoveControl.jsx → MoveControls/MoveControls.jsx} +10 -10
  319. package/src/App/components/{MoveControl/MoveControl.module.scss → MoveControls/MoveControls.module.scss} +60 -29
  320. package/src/App/components/{MoveControl/MoveControl.test.jsx → MoveControls/MoveControls.test.jsx} +48 -48
  321. package/src/App/components/Panel/Panel.jsx +18 -3
  322. package/src/App/components/Panel/Panel.module.scss +18 -8
  323. package/src/App/components/Panel/Panel.test.jsx +34 -0
  324. package/src/App/components/Tooltip/Tooltip.test.jsx +12 -14
  325. package/src/App/components/Viewport/Viewport.jsx +9 -1
  326. package/src/App/components/Viewport/Viewport.test.jsx +11 -0
  327. package/src/App/hooks/useFeatureItems.js +16 -7
  328. package/src/App/hooks/useFeatureItems.test.js +57 -0
  329. package/src/App/hooks/useLayoutMeasurements.js +95 -84
  330. package/src/App/hooks/useLayoutMeasurements.test.js +61 -1
  331. package/src/App/initialiseApp.js +11 -8
  332. package/src/App/initialiseApp.test.js +15 -3
  333. package/src/App/layout/Layout.jsx +12 -11
  334. package/src/App/layout/Layout.test.jsx +2 -0
  335. package/src/App/layout/layout.module.scss +31 -17
  336. package/src/App/registry/keyboardShortcutRegistry.js +25 -13
  337. package/src/App/registry/keyboardShortcutRegistry.test.js +49 -32
  338. package/src/App/registry/pluginRegistry.js +2 -3
  339. package/src/App/registry/pluginRegistry.test.js +16 -3
  340. package/src/App/renderer/HtmlElementHost.jsx +18 -5
  341. package/src/App/renderer/HtmlElementHost.test.jsx +54 -0
  342. package/src/App/renderer/mapButtons.js +28 -12
  343. package/src/App/renderer/mapButtons.test.js +17 -4
  344. package/src/App/renderer/mapControls.js +3 -1
  345. package/src/App/renderer/mapControls.test.js +16 -0
  346. package/src/App/renderer/mapPanels.js +44 -9
  347. package/src/App/renderer/mapPanels.test.js +51 -2
  348. package/src/App/renderer/orderItems.js +28 -0
  349. package/src/App/renderer/orderItems.test.js +50 -0
  350. package/src/App/renderer/slotAggregator.js +2 -18
  351. package/src/App/renderer/slotHelpers.js +3 -1
  352. package/src/App/renderer/slotHelpers.test.js +5 -0
  353. package/src/App/renderer/slots.js +3 -0
  354. package/src/App/store/AppProvider.jsx +4 -2
  355. package/src/App/store/appDispatchMiddleware.js +1 -1
  356. package/src/App/store/appDispatchMiddleware.test.js +8 -0
  357. package/src/InteractiveMap/InteractiveMap.js +8 -2
  358. package/src/InteractiveMap/InteractiveMap.test.js +20 -3
  359. package/src/config/appConfig.js +17 -15
  360. package/src/config/appConfig.test.js +22 -22
  361. package/src/config/defaults.js +3 -1
  362. package/src/config/events.js +2 -0
  363. package/src/config/mergeConfig.js +7 -0
  364. package/src/config/mergeConfig.test.js +20 -0
  365. package/src/scss/main.scss +1 -1
  366. package/src/scss/settings/_colors.scss +1 -0
  367. package/src/scss/settings/_dimensions.scss +2 -3
  368. package/src/scss/settings/_transition.scss +1 -1
  369. package/src/services/eventBus.js +44 -0
  370. package/src/services/eventBus.test.js +83 -0
  371. package/src/services/symbolRegistry.js +1 -1
  372. package/src/test-utils.js +5 -0
  373. package/src/types.js +25 -7
  374. package/webpack.umd.mjs +2 -0
  375. package/plugins/datasets/src/components/Key/EmptyKey.jsx +0 -7
  376. package/plugins/datasets/src/components/Key/Key.jsx +0 -50
  377. package/plugins/datasets/src/components/Key/KeyGroupItem.jsx +0 -18
  378. package/plugins/datasets/src/components/Key/KeyItem.jsx +0 -23
  379. package/plugins/datasets/src/components/Key/KeySvg.jsx +0 -22
  380. package/plugins/datasets/src/components/Key/KeySvgLine.jsx +0 -19
  381. package/plugins/datasets/src/components/Key/KeySvgPattern.jsx +0 -13
  382. package/plugins/datasets/src/components/Key/KeySvgRect.jsx +0 -22
  383. package/plugins/datasets/src/components/Key/KeySvgSymbol.jsx +0 -16
  384. package/plugins/datasets/src/components/LayersMenu/LayersRadioGroupWrapper.jsx +0 -41
  385. /package/plugins/{datasets → menu}/src/reducers/menuStateReducer.js +0 -0
  386. /package/{providers/maplibre/src → src}/utils/rasteriseToImageData.js +0 -0
  387. /package/{providers/maplibre/src → src}/utils/rasteriseToImageData.test.js +0 -0
@@ -2,7 +2,6 @@ import { render } from '@testing-library/react'
2
2
  import { KeySvg } from './KeySvg'
3
3
 
4
4
  import { symbolRegistry } from '../../../../../src/services/symbolRegistry.js'
5
- import { patternRegistry } from '../../../../../src/services/patternRegistry.js'
6
5
 
7
6
  const getSymbolDef = jest.spyOn(symbolRegistry, 'getSymbolDef')
8
7
 
@@ -22,17 +21,15 @@ jest.mock('./KeySvgRect.jsx', () => ({
22
21
  KeySvgRect: () => <svg data-testid='key-svg-rect' />
23
22
  }))
24
23
 
25
- const baseRegistryDataset = {
24
+ const baseKeyDefinition = {
26
25
  hasSymbol: false,
27
26
  hasPattern: false,
28
27
  style: {}
29
28
  }
30
29
 
31
30
  const baseProps = {
32
- symbolRegistry,
33
- patternRegistry,
34
31
  mapStyle: { id: 'default' },
35
- registryDataset: baseRegistryDataset
32
+ keyDefinition: baseKeyDefinition
36
33
  }
37
34
 
38
35
  beforeEach(() => {
@@ -42,17 +39,17 @@ beforeEach(() => {
42
39
  describe('KeySvg', () => {
43
40
  it('renders KeySvgSymbol when a symbolDef is resolved', () => {
44
41
  getSymbolDef.mockReturnValue({ id: 'marker' })
45
- const { getByTestId } = render(<KeySvg {...baseProps} registryDataset={{ ...baseRegistryDataset, hasSymbol: true }} />)
42
+ const { getByTestId } = render(<KeySvg {...baseProps} keyDefinition={{ ...baseKeyDefinition, hasSymbol: true }} />)
46
43
  expect(getByTestId('key-svg-symbol')).toBeTruthy()
47
44
  })
48
45
 
49
46
  it('renders KeySvgPattern when hasPattern is true and no symbol', () => {
50
- const { getByTestId } = render(<KeySvg {...baseProps} registryDataset={{ ...baseRegistryDataset, hasPattern: true }} />)
47
+ const { getByTestId } = render(<KeySvg {...baseProps} keyDefinition={{ ...baseKeyDefinition, hasPattern: true }} />)
51
48
  expect(getByTestId('key-svg-pattern')).toBeTruthy()
52
49
  })
53
50
 
54
51
  it('renders KeySvgLine when keySymbolShape is line and no symbol or pattern', () => {
55
- const { getByTestId } = render(<KeySvg {...baseProps} registryDataset={{ ...baseRegistryDataset, style: { keySymbolShape: 'line' } }} />)
52
+ const { getByTestId } = render(<KeySvg {...baseProps} keyDefinition={{ ...baseKeyDefinition, style: { keySymbolShape: 'line' } }} />)
56
53
  expect(getByTestId('key-svg-line')).toBeTruthy()
57
54
  })
58
55
 
@@ -63,25 +60,30 @@ describe('KeySvg', () => {
63
60
 
64
61
  it('prefers symbol over pattern when both are present', () => {
65
62
  getSymbolDef.mockReturnValue({ id: 'marker' })
66
- const { getByTestId, queryByTestId } = render(<KeySvg {...baseProps} registryDataset={{ ...baseRegistryDataset, hasSymbol: true, hasPattern: true }} />)
63
+ const { getByTestId, queryByTestId } = render(<KeySvg {...baseProps} keyDefinition={{ ...baseKeyDefinition, hasSymbol: true, hasPattern: true }} />)
67
64
  expect(getByTestId('key-svg-symbol')).toBeTruthy()
68
65
  expect(queryByTestId('key-svg-pattern')).toBeNull()
69
66
  })
70
67
 
71
68
  it('prefers pattern over line when both conditions are met', () => {
72
- const { getByTestId, queryByTestId } = render(<KeySvg {...baseProps} registryDataset={{ ...baseRegistryDataset, hasPattern: true, style: { keySymbolShape: 'line' } }} />)
69
+ const { getByTestId, queryByTestId } = render(<KeySvg {...baseProps} keyDefinition={{ ...baseKeyDefinition, hasPattern: true, style: { keySymbolShape: 'line' } }} />)
73
70
  expect(getByTestId('key-svg-pattern')).toBeTruthy()
74
71
  expect(queryByTestId('key-svg-line')).toBeNull()
75
72
  })
76
73
 
77
74
  it('renders KeySvgRect when keySymbolShape is not line and no symbol or pattern', () => {
78
- const { getByTestId } = render(<KeySvg {...baseProps} registryDataset={{ ...baseRegistryDataset, style: { keySymbolShape: 'polygon' } }} />)
75
+ const { getByTestId } = render(<KeySvg {...baseProps} keyDefinition={{ ...baseKeyDefinition, style: { keySymbolShape: 'polygon' } }} />)
79
76
  expect(getByTestId('key-svg-rect')).toBeTruthy()
80
77
  })
81
78
 
82
79
  it('does not render KeySvgSymbol when hasSymbol is true but getSymbolDef returns null', () => {
83
80
  getSymbolDef.mockReturnValue(null)
84
- const { getByTestId } = render(<KeySvg {...baseProps} registryDataset={{ ...baseRegistryDataset, hasSymbol: true }} />)
81
+ const { getByTestId } = render(<KeySvg {...baseProps} keyDefinition={{ ...baseKeyDefinition, hasSymbol: true }} />)
85
82
  expect(getByTestId('key-svg-rect')).toBeTruthy()
86
83
  })
84
+
85
+ it('should return null if keyDefinition is undefined', () => {
86
+ const { container } = render(<KeySvg {...baseProps} keyDefinition={null} />)
87
+ expect(container.firstChild).toBeNull()
88
+ })
87
89
  })
@@ -0,0 +1,28 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { svgProps, SVG_SIZE, SVG_CENTER } from './svgProperties.js'
3
+ import { getValueForStyle } from '../../../../../src/utils/getValueForStyle.js'
4
+
5
+ export const KeySvgLine = ({ mapStyle, keyDefinition }) => {
6
+ const [strokeWidth, setStrokeWidth] = useState(2)
7
+ const [stroke, setStroke] = useState('#ff0000')
8
+
9
+ useEffect(() => {
10
+ const { style } = keyDefinition
11
+ setStrokeWidth(style.strokeWidth)
12
+ setStroke(getValueForStyle(style.stroke, mapStyle.id))
13
+ }, [mapStyle.id, keyDefinition])
14
+
15
+ return (
16
+ <svg {...svgProps}>
17
+ <line
18
+ x1={strokeWidth / 2}
19
+ y1={SVG_CENTER}
20
+ x2={SVG_SIZE - strokeWidth / 2}
21
+ y2={SVG_CENTER}
22
+ stroke={stroke}
23
+ strokeWidth={strokeWidth}
24
+ strokeLinecap='round'
25
+ />
26
+ </svg>
27
+ )
28
+ }
@@ -8,7 +8,7 @@ jest.mock('../../../../../src/utils/getValueForStyle', () => ({
8
8
  }))
9
9
 
10
10
  const defaultProps = {
11
- registryDataset: {
11
+ keyDefinition: {
12
12
  style: {
13
13
  stroke: '#ff0000',
14
14
  strokeWidth: 2
@@ -0,0 +1,23 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { svgProps } from './svgProperties.js'
3
+ import { patternRegistry } from '../../registry/index.js'
4
+ const PATTERN_INSET = 2
5
+
6
+ export const KeySvgPattern = ({ keyDefinition, mapStyle }) => {
7
+ const [paths, setPaths] = useState(null)
8
+
9
+ useEffect(() => {
10
+ const { style } = keyDefinition
11
+ setPaths(patternRegistry.getKeyPatternPaths(style, mapStyle.id))
12
+ }, [mapStyle.id, keyDefinition])
13
+
14
+ if (!paths) {
15
+ return null
16
+ }
17
+ return (
18
+ <svg {...svgProps}>
19
+ <g dangerouslySetInnerHTML={{ __html: paths.border }} />
20
+ <g transform={`translate(${PATTERN_INSET}, ${PATTERN_INSET})`} dangerouslySetInnerHTML={{ __html: paths.content }} />
21
+ </svg>
22
+ )
23
+ }
@@ -4,7 +4,7 @@ import { patternRegistry } from '../../../../../src/services/patternRegistry.js'
4
4
 
5
5
  const getKeyPatternPaths = jest.spyOn(patternRegistry, 'getKeyPatternPaths')
6
6
  const defaultProps = {
7
- registryDataset: {
7
+ keyDefinition: {
8
8
  style: {
9
9
  fillPattern: 'dots'
10
10
  }
@@ -25,7 +25,7 @@ describe('KeySvgPattern', () => {
25
25
 
26
26
  it('calls getKeyPatternPaths with props, the mapStyle id, and the patternRegistry', () => {
27
27
  render(<KeySvgPattern {...defaultProps} />)
28
- expect(getKeyPatternPaths).toHaveBeenCalledWith(defaultProps.registryDataset.style, 'default')
28
+ expect(getKeyPatternPaths).toHaveBeenCalledWith(defaultProps.keyDefinition.style, 'default')
29
29
  })
30
30
 
31
31
  it('renders two g elements for border and content', () => {
@@ -0,0 +1,33 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { getValueForStyle } from '../../../../../src/utils/getValueForStyle.js'
3
+ import { svgProps, SVG_SIZE } from './svgProperties.js'
4
+
5
+ export const KeySvgRect = ({ mapStyle, keyDefinition }) => {
6
+ const [strokeWidth, setStrokeWidth] = useState(2)
7
+ const [fill, setFill] = useState('#ff0000')
8
+ const [stroke, setStroke] = useState('#ff0000')
9
+
10
+ useEffect(() => {
11
+ const { style } = keyDefinition
12
+ setStrokeWidth(style.strokeWidth)
13
+ setFill(getValueForStyle(style.fill, mapStyle.id))
14
+ setStroke(getValueForStyle(style.stroke, mapStyle.id))
15
+ }, [mapStyle.id, keyDefinition])
16
+
17
+ return (
18
+ <svg {...svgProps}>
19
+ <rect
20
+ x={strokeWidth / 2}
21
+ y={strokeWidth / 2}
22
+ width={SVG_SIZE - strokeWidth}
23
+ height={SVG_SIZE - strokeWidth}
24
+ rx={strokeWidth}
25
+ ry={strokeWidth}
26
+ fill={fill}
27
+ stroke={stroke}
28
+ strokeWidth={strokeWidth}
29
+ strokeLinejoin='round'
30
+ />
31
+ </svg>
32
+ )
33
+ }
@@ -8,7 +8,7 @@ jest.mock('../../../../../src/utils/getValueForStyle', () => ({
8
8
  }))
9
9
 
10
10
  const defaultProps = {
11
- registryDataset: {
11
+ keyDefinition: {
12
12
  style: {
13
13
  fill: '#0000ff',
14
14
  stroke: '#ff0000',
@@ -0,0 +1,27 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { getSymbolStyleColors, getSymbolViewBox } from '../../../../../src/utils/symbolUtils.js'
3
+ import { svgSymbolProps } from './svgProperties.js'
4
+ import { symbolRegistry } from '../../registry/index.js'
5
+
6
+ export const KeySvgSymbol = ({ keyDefinition, mapStyle, symbolDef }) => {
7
+ const [resolvedSvg, setResolvedSvg] = useState(null)
8
+ const [viewBox, setViewBox] = useState(null)
9
+
10
+ useEffect(() => {
11
+ const { style } = keyDefinition
12
+ const mapColorScheme = mapStyle?.appColorScheme ?? 'light'
13
+ const keyMapStyle = { ...mapStyle, mapColorScheme }
14
+ setResolvedSvg(symbolRegistry.resolve(symbolDef, getSymbolStyleColors(style), keyMapStyle))
15
+ setViewBox(getSymbolViewBox(style, symbolDef))
16
+ }, [mapStyle, keyDefinition])
17
+
18
+ if (!(resolvedSvg && viewBox)) {
19
+ return null
20
+ }
21
+
22
+ return (
23
+ <svg {...svgSymbolProps} viewBox={viewBox}>
24
+ <g dangerouslySetInnerHTML={{ __html: resolvedSvg }} />
25
+ </svg>
26
+ )
27
+ }
@@ -1,23 +1,22 @@
1
1
  import { render } from '@testing-library/react'
2
2
  import { KeySvgSymbol } from './KeySvgSymbol'
3
-
4
3
  import { getSymbolStyleColors, getSymbolViewBox } from '../../../../../src/utils/symbolUtils.js'
4
+ import { symbolRegistry } from '../../registry/index.js'
5
5
 
6
6
  jest.mock('../../../../../src/utils/symbolUtils.js', () => ({
7
7
  getSymbolStyleColors: jest.fn(() => ({ foreground: '#000', background: '#fff' })),
8
8
  getSymbolViewBox: jest.fn(() => '0 0 38 38')
9
9
  }))
10
10
 
11
- const mockResolve = jest.fn(() => '<path d="M0 0"/>')
11
+ const mockResolve = jest.spyOn(symbolRegistry, 'resolve')
12
12
 
13
13
  const defaultProps = {
14
14
  symbolDef: { id: 'marker' },
15
- registryDataset: {
15
+ keyDefinition: {
16
16
  style: {
17
17
  stroke: '#000000'
18
18
  }
19
19
  },
20
- symbolRegistry: { resolve: mockResolve },
21
20
  mapStyle: { id: 'default' }
22
21
  }
23
22
 
@@ -45,12 +44,12 @@ describe('KeySvgSymbol', () => {
45
44
 
46
45
  it('calls getSymbolStyleColors with the dataset props', () => {
47
46
  render(<KeySvgSymbol {...defaultProps} />)
48
- expect(getSymbolStyleColors).toHaveBeenCalledWith(defaultProps.registryDataset.style)
47
+ expect(getSymbolStyleColors).toHaveBeenCalledWith(defaultProps.keyDefinition.style)
49
48
  })
50
49
 
51
50
  it('calls getSymbolViewBox with the dataset props and symbolDef', () => {
52
51
  render(<KeySvgSymbol {...defaultProps} />)
53
- expect(getSymbolViewBox).toHaveBeenCalledWith(defaultProps.registryDataset.style, defaultProps.symbolDef)
52
+ expect(getSymbolViewBox).toHaveBeenCalledWith(defaultProps.keyDefinition.style, defaultProps.symbolDef)
54
53
  })
55
54
 
56
55
  it('sets the viewBox from getSymbolViewBox', () => {
@@ -0,0 +1,50 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import { getDatasetRegistry } from '../../registry/index.js'
3
+
4
+ import { Key } from './Key.jsx'
5
+
6
+ export function MapKey ({
7
+ mapState: { mapStyle },
8
+ pluginConfig: { noKeyItemText },
9
+ services: { eventBus }
10
+ }) {
11
+ const [keyGroups, setKeyGroups] = useState([])
12
+ const [hasGroups, setHasGroups] = useState(false)
13
+ const [datasetRegistry, setDatasetRegistry] = useState(getDatasetRegistry())
14
+
15
+ const getKeyItems = () => {
16
+ const { items, hasGroups: _hasGroups } = datasetRegistry.keyItems()
17
+ setKeyGroups(items)
18
+ setHasGroups(_hasGroups)
19
+ }
20
+
21
+ const onMenuChanged = (menuState) => {
22
+ datasetRegistry.invalidateKeyItemsOnMenuStateChange(menuState)
23
+ getKeyItems()
24
+ }
25
+
26
+ useEffect(() => {
27
+ if (!datasetRegistry) {
28
+ // 'datasets:registry' is only required when the key is opened before datasets:ready
29
+ eventBus.requestOnce('datasets:registry', setDatasetRegistry)
30
+ return () => {}
31
+ } else {
32
+ getKeyItems() // populate the initial KeyItems from the datasetRegistry (which caches them)
33
+ eventBus
34
+ .on('menu:changed', onMenuChanged) // Ensure keyItems refresh when menu updates
35
+ .on('datasets:changed', getKeyItems) // Ensure keyItems refresh when datasets change
36
+ return () => eventBus
37
+ .off('menu:changed', onMenuChanged)
38
+ .off('datasets:changed', getKeyItems)
39
+ }
40
+ }, [datasetRegistry])
41
+
42
+ return (
43
+ <Key
44
+ noKeyItemText={noKeyItemText}
45
+ keyGroups={keyGroups}
46
+ hasGroups={hasGroups}
47
+ mapStyle={mapStyle}
48
+ />
49
+ )
50
+ }
@@ -0,0 +1,130 @@
1
+ import { render, act } from '@testing-library/react'
2
+ import { MapKey } from './MapKey'
3
+ import { getDatasetRegistry } from '../../registry/index.js'
4
+
5
+ jest.mock('../../registry/index.js', () => ({
6
+ getDatasetRegistry: jest.fn()
7
+ }))
8
+
9
+ jest.mock('./Key.jsx', () => ({
10
+ Key: ({ noKeyItemText, keyGroups, hasGroups, mapStyle }) => (
11
+ <div
12
+ data-testid='key'
13
+ data-no-key-item-text={noKeyItemText}
14
+ data-has-groups={String(hasGroups)}
15
+ data-map-style-id={mapStyle.id}
16
+ data-key-groups-length={keyGroups.length}
17
+ />
18
+ )
19
+ }))
20
+
21
+ const makeEventBus = () => {
22
+ const eventBus = {
23
+ requestOnce: jest.fn(),
24
+ on: jest.fn(),
25
+ off: jest.fn()
26
+ }
27
+ eventBus.on.mockReturnValue(eventBus)
28
+ eventBus.off.mockReturnValue(eventBus)
29
+ return eventBus
30
+ }
31
+
32
+ const makeRegistry = (items = [], hasGroups = false) => ({
33
+ keyItems: jest.fn().mockReturnValue({ items, hasGroups }),
34
+ invalidateKeyItemsOnMenuStateChange: jest.fn()
35
+ })
36
+
37
+ let eventBus
38
+ const baseProps = () => ({
39
+ mapState: { mapStyle: { id: 'default' } },
40
+ pluginConfig: { noKeyItemText: 'No items' },
41
+ services: { eventBus }
42
+ })
43
+
44
+ beforeEach(() => {
45
+ jest.clearAllMocks()
46
+ eventBus = makeEventBus()
47
+ })
48
+
49
+ describe('MapKey', () => {
50
+ describe('when datasetRegistry is null', () => {
51
+ beforeEach(() => { getDatasetRegistry.mockReturnValue(null) })
52
+
53
+ it('passes empty items and hasGroups false to Key', () => {
54
+ const { getByTestId } = render(<MapKey {...baseProps()} />)
55
+ expect(getByTestId('key').dataset.keyGroupsLength).toBe('0')
56
+ expect(getByTestId('key').dataset.hasGroups).toBe('false')
57
+ })
58
+
59
+ it('calls requestOnce for datasets:registry', () => {
60
+ render(<MapKey {...baseProps()} />)
61
+ expect(eventBus.requestOnce).toHaveBeenCalledWith('datasets:registry', expect.any(Function))
62
+ })
63
+
64
+ it('populates key items when the registry arrives via requestOnce', () => {
65
+ render(<MapKey {...baseProps()} />)
66
+ const setReg = eventBus.requestOnce.mock.calls[0][1]
67
+ const registry = makeRegistry([{ id: '1' }, { id: '2' }], true)
68
+ act(() => { setReg(registry) })
69
+ expect(registry.keyItems).toHaveBeenCalled()
70
+ })
71
+ })
72
+
73
+ describe('when datasetRegistry exists', () => {
74
+ let registry
75
+
76
+ beforeEach(() => {
77
+ registry = makeRegistry([{ id: '1' }, { id: '2' }], true)
78
+ getDatasetRegistry.mockReturnValue(registry)
79
+ })
80
+
81
+ it('passes keyGroups and hasGroups from the registry to Key', () => {
82
+ const { getByTestId } = render(<MapKey {...baseProps()} />)
83
+ expect(getByTestId('key').dataset.keyGroupsLength).toBe('2')
84
+ expect(getByTestId('key').dataset.hasGroups).toBe('true')
85
+ })
86
+
87
+ it('registers menu:changed and datasets:changed listeners', () => {
88
+ render(<MapKey {...baseProps()} />)
89
+ expect(eventBus.on).toHaveBeenCalledWith('menu:changed', expect.any(Function))
90
+ expect(eventBus.on).toHaveBeenCalledWith('datasets:changed', expect.any(Function))
91
+ })
92
+
93
+ it('deregisters listeners on unmount', () => {
94
+ const { unmount } = render(<MapKey {...baseProps()} />)
95
+ unmount()
96
+ expect(eventBus.off).toHaveBeenCalledWith('menu:changed', expect.any(Function))
97
+ expect(eventBus.off).toHaveBeenCalledWith('datasets:changed', expect.any(Function))
98
+ })
99
+
100
+ it('refreshes key items when datasets:changed fires', () => {
101
+ render(<MapKey {...baseProps()} />)
102
+ const onDatasetsChanged = eventBus.on.mock.calls.find(([e]) => e === 'datasets:changed')[1]
103
+ act(() => { onDatasetsChanged() })
104
+ expect(registry.keyItems).toHaveBeenCalledTimes(2)
105
+ })
106
+
107
+ it('invalidates and refreshes key items when menu:changed fires', () => {
108
+ render(<MapKey {...baseProps()} />)
109
+ const onMenuChanged = eventBus.on.mock.calls.find(([e]) => e === 'menu:changed')[1]
110
+ const menuState = { someKey: 'value' }
111
+ act(() => { onMenuChanged(menuState) })
112
+ expect(registry.invalidateKeyItemsOnMenuStateChange).toHaveBeenCalledWith(menuState)
113
+ expect(registry.keyItems).toHaveBeenCalledTimes(2)
114
+ })
115
+ })
116
+
117
+ describe('props forwarded to Key', () => {
118
+ beforeEach(() => { getDatasetRegistry.mockReturnValue(null) })
119
+
120
+ it('passes noKeyItemText from pluginConfig', () => {
121
+ const { getByTestId } = render(<MapKey {...baseProps()} />)
122
+ expect(getByTestId('key').dataset.noKeyItemText).toBe('No items')
123
+ })
124
+
125
+ it('passes mapStyle from mapState', () => {
126
+ const { getByTestId } = render(<MapKey {...baseProps()} />)
127
+ expect(getByTestId('key').dataset.mapStyleId).toBe('default')
128
+ })
129
+ })
130
+ })
@@ -7,7 +7,7 @@ export const svgProps = {
7
7
  width: SVG_SIZE,
8
8
  height: SVG_SIZE,
9
9
  viewBox: `0 0 ${SVG_SIZE} ${SVG_SIZE}`,
10
- className: 'am-c-datasets-key-symbol',
10
+ className: 'am-c-map-key-symbol',
11
11
  'aria-hidden': 'true',
12
12
  focusable: 'false'
13
13
  }
@@ -16,5 +16,5 @@ export const svgSymbolProps = {
16
16
  ...svgProps,
17
17
  width: SVG_SYMBOL_SIZE,
18
18
  height: SVG_SYMBOL_SIZE,
19
- className: 'am-c-datasets-key-symbol am-c-datasets-key-symbol--point'
19
+ className: 'am-c-map-key-symbol am-c-map-key-symbol--point'
20
20
  }
@@ -25,7 +25,7 @@ describe('svgProps', () => {
25
25
  })
26
26
 
27
27
  it('has the correct className', () => {
28
- expect(svgProps.className).toBe('am-c-datasets-key-symbol')
28
+ expect(svgProps.className).toBe('am-c-map-key-symbol')
29
29
  })
30
30
 
31
31
  it('is aria-hidden', () => {
@@ -55,7 +55,7 @@ describe('svgSymbolProps', () => {
55
55
  })
56
56
 
57
57
  it('className includes the base class and a modifier', () => {
58
- expect(svgSymbolProps.className).toContain('am-c-datasets-key-symbol')
58
+ expect(svgSymbolProps.className).toContain('am-c-map-key-symbol')
59
59
  expect(svgSymbolProps.className).toContain('--point')
60
60
  })
61
61
  })
@@ -0,0 +1,13 @@
1
+ import './mapKey.scss'
2
+
3
+ export default function createPlugin (options = {}) {
4
+ return {
5
+ noKeyItemText: 'No features displayed',
6
+ ...options,
7
+ id: 'mapKey',
8
+ load: async () => {
9
+ const module = (await import(/* webpackChunkName: "im-map-key-plugin" */ './manifest.js')).manifest
10
+ return module
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,31 @@
1
+ import createPlugin from './index.js'
2
+
3
+ jest.mock('./mapKey.scss', () => {})
4
+ jest.mock('./manifest.js', () => ({ manifest: { InitComponent: 'MapKeyInit', panels: [] } }))
5
+
6
+ describe('createPlugin', () => {
7
+ it('returns the mapKey id', () => {
8
+ expect(createPlugin().id).toBe('mapKey')
9
+ })
10
+
11
+ it('id cannot be overridden by options', () => {
12
+ expect(createPlugin({ id: 'other' }).id).toBe('mapKey')
13
+ })
14
+
15
+ it('returns the default noKeyItemText', () => {
16
+ expect(createPlugin().noKeyItemText).toBe('No features displayed')
17
+ })
18
+
19
+ it('allows noKeyItemText to be overridden', () => {
20
+ expect(createPlugin({ noKeyItemText: 'Nothing here' }).noKeyItemText).toBe('Nothing here')
21
+ })
22
+
23
+ it('merges additional options into the returned object', () => {
24
+ expect(createPlugin({ custom: true }).custom).toBe(true)
25
+ })
26
+
27
+ it('load() resolves to the manifest', async () => {
28
+ const result = await createPlugin().load()
29
+ expect(result).toEqual({ InitComponent: 'MapKeyInit', panels: [] })
30
+ })
31
+ })
@@ -0,0 +1,15 @@
1
+ import { useEffect } from 'react'
2
+ import { setDatasetRegistry } from '../registry/getDatasetRegistry.js'
3
+
4
+ // additional possible params here are: pluginConfig, pluginState, appState, mapProvider,
5
+ export function MapKeyInit ({ mapState, services }) {
6
+ const { eventBus } = services
7
+
8
+ useEffect(() => {
9
+ if (!mapState.isMapReady) {
10
+ return
11
+ }
12
+ // Request a handle on the datasetsRegistry singleton
13
+ eventBus.requestOnce('datasets:registry', setDatasetRegistry)
14
+ }, [mapState.isMapReady])
15
+ }
@@ -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
+ }