@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
@@ -1,2 +1,2 @@
1
1
  /*! For license information please see index.js.LICENSE.txt */
2
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("defra",[],t):"object"==typeof exports?exports.defra=t():(e.defra=e.defra||{},e.defra.interactPlugin=t())}(this,()=>(()=>{"use strict";var e,t,r={738(e){e.exports=preactCompat},287(e){e.exports=preactJsxRuntime}},n={};function o(e){var t=n[e];if(void 0!==t)return t.exports;var i=n[e]={exports:{}};return r[e](i,i.exports,o),i.exports}o.m=r,o.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},o.d=(e,t)=>{for(var r in t)o.o(t,r)&&!o.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce((t,r)=>(o.f[r](e,t),t),[])),o.u=e=>"im-interact-plugin.js",o.miniCssF=e=>{},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),e={},t="defra.interactPlugin:",o.l=(r,n,i,a)=>{if(e[r])e[r].push(n);else{var u,c;if(void 0!==i)for(var f=document.getElementsByTagName("script"),p=0;p<f.length;p++){var l=f[p];if(l.getAttribute("src")==r||l.getAttribute("data-webpack")==t+i){u=l;break}}u||(c=!0,(u=document.createElement("script")).charset="utf-8",o.nc&&u.setAttribute("nonce",o.nc),u.setAttribute("data-webpack",t+i),u.src=r),e[r]=[n];var s=(t,n)=>{u.onerror=u.onload=null,clearTimeout(d);var o=e[r];if(delete e[r],u.parentNode&&u.parentNode.removeChild(u),o&&o.forEach(e=>e(n)),t)return t(n)},d=setTimeout(s.bind(null,void 0,{type:"timeout",target:u}),12e4);u.onerror=s.bind(null,u.onerror),u.onload=s.bind(null,u.onload),c&&document.head.appendChild(u)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+"");var t=o.g.document;if(!e&&t&&(t.currentScript&&"SCRIPT"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName("script");if(r.length)for(var n=r.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=r[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),o.p=e})(),(()=>{var e={57:0};o.f.j=(t,r)=>{var n=o.o(e,t)?e[t]:void 0;if(0!==n)if(n)r.push(n[2]);else{var i=new Promise((r,o)=>n=e[t]=[r,o]);r.push(n[2]=i);var a=o.p+o.u(t),u=new Error;o.l(a,r=>{if(o.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var i=r&&("load"===r.type?"missing":r.type),a=r&&r.target&&r.target.src;u.message="Loading chunk "+t+" failed.\n("+i+": "+a+")",u.name="ChunkLoadError",u.type=i,u.request=a,n[1](u)}},"chunk-"+t,t)}};var t=(t,r)=>{var n,i,[a,u,c]=r,f=0;if(a.some(t=>0!==e[t])){for(n in u)o.o(u,n)&&(o.m[n]=u[n]);c&&c(o)}for(t&&t(r);f<a.length;f++)i=a[f],o.o(e,i)&&e[i]&&e[i][0](),e[i]=0},r=this.webpackChunkdefra_DefraMap=this.webpackChunkdefra_DefraMap||[];r.forEach(t.bind(null,0)),r.push=t.bind(null,r.push.bind(r))})();var i={};function a(e){return a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a(e)}function u(){var e,t,r="function"==typeof Symbol?Symbol:{},n=r.iterator||"@@iterator",o=r.toStringTag||"@@toStringTag";function i(r,n,o,i){var u=n&&n.prototype instanceof f?n:f,p=Object.create(u.prototype);return c(p,"_invoke",function(r,n,o){var i,u,c,f=0,p=o||[],l=!1,s={p:0,n:0,v:e,a:d,f:d.bind(e,4),d:function(t,r){return i=t,u=0,c=e,s.n=r,a}};function d(r,n){for(u=r,c=n,t=0;!l&&f&&!o&&t<p.length;t++){var o,i=p[t],d=s.p,b=i[2];r>3?(o=b===n)&&(c=i[(u=i[4])?5:(u=3,3)],i[4]=i[5]=e):i[0]<=d&&((o=r<2&&d<i[1])?(u=0,s.v=n,s.n=i[1]):d<b&&(o=r<3||i[0]>n||n>b)&&(i[4]=r,i[5]=n,s.n=b,u=0))}if(o||r>1)return a;throw l=!0,n}return function(o,p,b){if(f>1)throw TypeError("Generator is already running");for(l&&1===p&&d(p,b),u=p,c=b;(t=u<2?e:c)||!l;){i||(u?u<3?(u>1&&(s.n=-1),d(u,c)):s.n=c:s.v=c);try{if(f=2,i){if(u||(o="next"),t=i[o]){if(!(t=t.call(i,c)))throw TypeError("iterator result is not an object");if(!t.done)return t;c=t.value,u<2&&(u=0)}else 1===u&&(t=i.return)&&t.call(i),u<2&&(c=TypeError("The iterator does not provide a '"+o+"' method"),u=1);i=e}else if((t=(l=s.n<0)?c:r.call(n,s))!==a)break}catch(t){i=e,u=1,c=t}finally{f=1}}return{value:t,done:l}}}(r,o,i),!0),p}var a={};function f(){}function p(){}function l(){}t=Object.getPrototypeOf;var s=[][n]?t(t([][n]())):(c(t={},n,function(){return this}),t),d=l.prototype=f.prototype=Object.create(s);function b(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,l):(e.__proto__=l,c(e,o,"GeneratorFunction")),e.prototype=Object.create(d),e}return p.prototype=l,c(d,"constructor",l),c(l,"constructor",p),p.displayName="GeneratorFunction",c(l,o,"GeneratorFunction"),c(d),c(d,o,"Generator"),c(d,n,function(){return this}),c(d,"toString",function(){return"[object Generator]"}),(u=function(){return{w:i,m:b}})()}function c(e,t,r,n){var o=Object.defineProperty;try{o({},"",{})}catch(e){o=0}c=function(e,t,r,n){function i(t,r){c(e,t,function(e){return this._invoke(t,r,e)})}t?o?o(e,t,{value:r,enumerable:!n,configurable:!n,writable:!n}):e[t]=r:(i("next",0),i("throw",1),i("return",2))},c(e,t,r,n)}function f(e,t,r,n,o,i,a){try{var u=e[i](a),c=u.value}catch(e){return void r(e)}u.done?t(c):Promise.resolve(c).then(n,o)}function p(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,n)}return r}function l(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?p(Object(r),!0).forEach(function(t){s(e,t,r[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):p(Object(r)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})}return e}function s(e,t,r){return(t=function(e){var t=function(e){if("object"!=a(e)||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var r=t.call(e,"string");if("object"!=a(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==a(t)?t:t+""}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function d(){var e,t;return l(l({},arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),{},{id:"interact",load:(e=u().m(function e(){var t;return u().w(function(e){for(;;)switch(e.n){case 0:return e.n=1,o.e(936).then(o.bind(o,77));case 1:return t=e.v.manifest,e.a(2,t)}},e)}),t=function(){var t=this,r=arguments;return new Promise(function(n,o){var i=e.apply(t,r);function a(e){f(i,n,o,a,u,"next",e)}function u(e){f(i,n,o,a,u,"throw",e)}a(void 0)})},function(){return t.apply(this,arguments)})})}return o.d(i,{default:()=>d}),i.default})());
2
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("defra",[],t):"object"==typeof exports?exports.defra=t():(e.defra=e.defra||{},e.defra.interactPlugin=t())}(this,()=>(()=>{"use strict";var e,t,r={738(e){e.exports=preactCompat},287(e){e.exports=preactJsxRuntime}},n={};function o(e){var t=n[e];if(void 0!==t)return t.exports;var i=n[e]={exports:{}};return r[e](i,i.exports,o),i.exports}o.m=r,o.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},o.d=(e,t)=>{for(var r in t)o.o(t,r)&&!o.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce((t,r)=>(o.f[r](e,t),t),[])),o.u=e=>"im-interact-plugin.js",o.miniCssF=e=>{},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),e={},t="defra.interactPlugin:",o.l=(r,n,i,a)=>{if(e[r])e[r].push(n);else{var u,c;if(void 0!==i)for(var f=document.getElementsByTagName("script"),p=0;p<f.length;p++){var l=f[p];if(l.getAttribute("src")==r||l.getAttribute("data-webpack")==t+i){u=l;break}}u||(c=!0,(u=document.createElement("script")).charset="utf-8",o.nc&&u.setAttribute("nonce",o.nc),u.setAttribute("data-webpack",t+i),u.src=r),e[r]=[n];var s=(t,n)=>{u.onerror=u.onload=null,clearTimeout(d);var o=e[r];if(delete e[r],u.parentNode&&u.parentNode.removeChild(u),o&&o.forEach(e=>e(n)),t)return t(n)},d=setTimeout(s.bind(null,void 0,{type:"timeout",target:u}),12e4);u.onerror=s.bind(null,u.onerror),u.onload=s.bind(null,u.onload),c&&document.head.appendChild(u)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+"");var t=o.g.document;if(!e&&t&&(t.currentScript&&"SCRIPT"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName("script");if(r.length)for(var n=r.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=r[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),o.p=e})(),(()=>{var e={57:0};o.f.j=(t,r)=>{var n=o.o(e,t)?e[t]:void 0;if(0!==n)if(n)r.push(n[2]);else{var i=new Promise((r,o)=>n=e[t]=[r,o]);r.push(n[2]=i);var a=o.p+o.u(t),u=new Error;o.l(a,r=>{if(o.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var i=r&&("load"===r.type?"missing":r.type),a=r&&r.target&&r.target.src;u.message="Loading chunk "+t+" failed.\n("+i+": "+a+")",u.name="ChunkLoadError",u.type=i,u.request=a,n[1](u)}},"chunk-"+t,t)}};var t=(t,r)=>{var n,i,[a,u,c]=r,f=0;if(a.some(t=>0!==e[t])){for(n in u)o.o(u,n)&&(o.m[n]=u[n]);c&&c(o)}for(t&&t(r);f<a.length;f++)i=a[f],o.o(e,i)&&e[i]&&e[i][0](),e[i]=0},r=this.webpackChunkdefra_DefraMap=this.webpackChunkdefra_DefraMap||[];r.forEach(t.bind(null,0)),r.push=t.bind(null,r.push.bind(r))})();var i={};function a(e){return a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a(e)}function u(){var e,t,r="function"==typeof Symbol?Symbol:{},n=r.iterator||"@@iterator",o=r.toStringTag||"@@toStringTag";function i(r,n,o,i){var u=n&&n.prototype instanceof f?n:f,p=Object.create(u.prototype);return c(p,"_invoke",function(r,n,o){var i,u,c,f=0,p=o||[],l=!1,s={p:0,n:0,v:e,a:d,f:d.bind(e,4),d:function(t,r){return i=t,u=0,c=e,s.n=r,a}};function d(r,n){for(u=r,c=n,t=0;!l&&f&&!o&&t<p.length;t++){var o,i=p[t],d=s.p,b=i[2];r>3?(o=b===n)&&(c=i[(u=i[4])?5:(u=3,3)],i[4]=i[5]=e):i[0]<=d&&((o=r<2&&d<i[1])?(u=0,s.v=n,s.n=i[1]):d<b&&(o=r<3||i[0]>n||n>b)&&(i[4]=r,i[5]=n,s.n=b,u=0))}if(o||r>1)return a;throw l=!0,n}return function(o,p,b){if(f>1)throw TypeError("Generator is already running");for(l&&1===p&&d(p,b),u=p,c=b;(t=u<2?e:c)||!l;){i||(u?u<3?(u>1&&(s.n=-1),d(u,c)):s.n=c:s.v=c);try{if(f=2,i){if(u||(o="next"),t=i[o]){if(!(t=t.call(i,c)))throw TypeError("iterator result is not an object");if(!t.done)return t;c=t.value,u<2&&(u=0)}else 1===u&&(t=i.return)&&t.call(i),u<2&&(c=TypeError("The iterator does not provide a '"+o+"' method"),u=1);i=e}else if((t=(l=s.n<0)?c:r.call(n,s))!==a)break}catch(t){i=e,u=1,c=t}finally{f=1}}return{value:t,done:l}}}(r,o,i),!0),p}var a={};function f(){}function p(){}function l(){}t=Object.getPrototypeOf;var s=[][n]?t(t([][n]())):(c(t={},n,function(){return this}),t),d=l.prototype=f.prototype=Object.create(s);function b(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,l):(e.__proto__=l,c(e,o,"GeneratorFunction")),e.prototype=Object.create(d),e}return p.prototype=l,c(d,"constructor",l),c(l,"constructor",p),p.displayName="GeneratorFunction",c(l,o,"GeneratorFunction"),c(d),c(d,o,"Generator"),c(d,n,function(){return this}),c(d,"toString",function(){return"[object Generator]"}),(u=function(){return{w:i,m:b}})()}function c(e,t,r,n){var o=Object.defineProperty;try{o({},"",{})}catch(e){o=0}c=function(e,t,r,n){function i(t,r){c(e,t,function(e){return this._invoke(t,r,e)})}t?o?o(e,t,{value:r,enumerable:!n,configurable:!n,writable:!n}):e[t]=r:(i("next",0),i("throw",1),i("return",2))},c(e,t,r,n)}function f(e,t,r,n,o,i,a){try{var u=e[i](a),c=u.value}catch(e){return void r(e)}u.done?t(c):Promise.resolve(c).then(n,o)}function p(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,n)}return r}function l(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?p(Object(r),!0).forEach(function(t){s(e,t,r[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):p(Object(r)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})}return e}function s(e,t,r){return(t=function(e){var t=function(e){if("object"!=a(e)||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var r=t.call(e,"string");if("object"!=a(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==a(t)?t:t+""}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function d(){var e,t;return l(l({},arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),{},{id:"interact",load:(e=u().m(function e(){var t;return u().w(function(e){for(;;)switch(e.n){case 0:return e.n=1,o.e(936).then(o.bind(o,394));case 1:return t=e.v.manifest,e.a(2,t)}},e)}),t=function(){var t=this,r=arguments;return new Promise(function(n,o){var i=e.apply(t,r);function a(e){f(i,n,o,a,u,"next",e)}function u(e){f(i,n,o,a,u,"throw",e)}a(void 0)})},function(){return t.apply(this,arguments)})})}return o.d(i,{default:()=>d}),i.default})());
@@ -8,13 +8,16 @@ export function useCrossHairVisibility ({ crossHair, enabled, selectMarkerOnly,
8
8
  const crossHairRef = useRef(crossHair)
9
9
  crossHairRef.current = crossHair
10
10
  const listboxFocusRef = useRef(false)
11
+ // True while focus is inside an element (marked `data-map-keyboard-scope`) that actually routes cursor keys to the map, e.g. the viewport or MoveControl's D-pad.
12
+ const mapKeyboardScopedRef = useRef(false)
11
13
  const interfaceTypeRef = useRef(appState.interfaceType)
12
14
  interfaceTypeRef.current = appState.interfaceType
13
15
 
14
16
  const updateCrossHair = useCallback(() => {
15
17
  const type = interfaceTypeRef.current
16
- const isToK = ['touch', 'keyboard'].includes(type)
17
- if (enabledRef.current && !listboxFocusRef.current && isToK && !(type === 'touch' && selectMarkerOnlyRef.current)) {
18
+ const keyboardCanOperateMap = type === 'keyboard' && mapKeyboardScopedRef.current
19
+ const touchCanOperateMap = type === 'touch' && !selectMarkerOnlyRef.current && !listboxFocusRef.current
20
+ if (enabledRef.current && (keyboardCanOperateMap || touchCanOperateMap)) {
18
21
  crossHairRef.current.fixAtCenter()
19
22
  } else {
20
23
  crossHairRef.current.hide()
@@ -28,10 +31,15 @@ export function useCrossHairVisibility ({ crossHair, enabled, selectMarkerOnly,
28
31
  useEffect(() => {
29
32
  const container = appState.layoutRefs?.appContainerRef?.current
30
33
  if (!container) { return undefined }
34
+ mapKeyboardScopedRef.current = !!document.activeElement?.closest('[data-map-keyboard-scope]')
31
35
  const handleFocusIn = (e) => {
32
36
  const inListbox = !!e.target.closest('[role="listbox"], [role="option"]')
33
- if (listboxFocusRef.current !== inListbox) {
34
- listboxFocusRef.current = inListbox
37
+ const inMapKeyboardScope = !!e.target.closest('[data-map-keyboard-scope]')
38
+ const changed = listboxFocusRef.current !== inListbox || mapKeyboardScopedRef.current !== inMapKeyboardScope
39
+ listboxFocusRef.current = inListbox
40
+ mapKeyboardScopedRef.current = inMapKeyboardScope
41
+ // Keep the refs current regardless, but only touch the crosshair while enabled — while disabled, another owner (e.g. draw mode) is responsible for it.
42
+ if (changed && enabledRef.current) {
35
43
  updateCrossHair()
36
44
  }
37
45
  }
@@ -19,7 +19,7 @@ describe('useCrossHairVisibility', () => {
19
19
  expect(crossHair.hide).toHaveBeenCalled()
20
20
  })
21
21
 
22
- it('shows crosshair on touch/keyboard and hides when listbox has focus', () => {
22
+ it('shows crosshair on touch and hides when listbox has focus', () => {
23
23
  const container = appState.layoutRefs.appContainerRef.current
24
24
  appState.interfaceType = 'touch'
25
25
  renderHook(() => useCrossHairVisibility({ crossHair, enabled: true, selectMarkerOnly: false, appState }))
@@ -46,4 +46,91 @@ describe('useCrossHairVisibility', () => {
46
46
  act(() => otherEl.dispatchEvent(new FocusEvent('focusin', { bubbles: true })))
47
47
  expect(crossHair.fixAtCenter).toHaveBeenCalledTimes(2)
48
48
  })
49
+
50
+ it('hides crosshair in keyboard mode until focus enters the map keyboard scope', () => {
51
+ const container = appState.layoutRefs.appContainerRef.current
52
+ const viewportEl = document.createElement('div')
53
+ viewportEl.setAttribute('data-map-keyboard-scope', '')
54
+ container.appendChild(viewportEl)
55
+ appState.interfaceType = 'keyboard'
56
+
57
+ renderHook(() => useCrossHairVisibility({ crossHair, enabled: true, selectMarkerOnly: false, appState }))
58
+
59
+ // interfaceType is 'keyboard' but nothing in the map keyboard scope has focus yet
60
+ expect(crossHair.hide).toHaveBeenCalled()
61
+ expect(crossHair.fixAtCenter).not.toHaveBeenCalled()
62
+
63
+ // Viewport gains focus — cursor keys now actually operate the map
64
+ act(() => viewportEl.dispatchEvent(new FocusEvent('focusin', { bubbles: true })))
65
+ expect(crossHair.fixAtCenter).toHaveBeenCalled()
66
+
67
+ // Focus moves elsewhere (e.g. a popup menu closed with Escape, which also
68
+ // flips interfaceType to 'keyboard' but shouldn't leave the crosshair up)
69
+ const menuEl = document.createElement('ul')
70
+ menuEl.setAttribute('role', 'menu')
71
+ container.appendChild(menuEl)
72
+ act(() => menuEl.dispatchEvent(new FocusEvent('focusin', { bubbles: true })))
73
+ expect(crossHair.hide).toHaveBeenCalledTimes(2)
74
+ })
75
+
76
+ it('shows the crosshair for a control (e.g. MoveControl) that forwards arrow keys to the map without moving DOM focus onto the viewport', () => {
77
+ const container = appState.layoutRefs.appContainerRef.current
78
+ const moveControlButton = document.createElement('button')
79
+ const moveControlScope = document.createElement('div')
80
+ moveControlScope.setAttribute('data-map-keyboard-scope', '')
81
+ moveControlScope.appendChild(moveControlButton)
82
+ container.appendChild(moveControlScope)
83
+ appState.interfaceType = 'keyboard'
84
+
85
+ renderHook(() => useCrossHairVisibility({ crossHair, enabled: true, selectMarkerOnly: false, appState }))
86
+ expect(crossHair.fixAtCenter).not.toHaveBeenCalled()
87
+
88
+ // Focus lands on a direction button nested inside the scoped control, not
89
+ // on the scope element itself — closest() must still pick it up.
90
+ act(() => moveControlButton.dispatchEvent(new FocusEvent('focusin', { bubbles: true })))
91
+ expect(crossHair.fixAtCenter).toHaveBeenCalled()
92
+ })
93
+
94
+ it('does not touch the crosshair on a focus change while disabled, leaving another owner (e.g. draw mode) in control', () => {
95
+ const container = appState.layoutRefs.appContainerRef.current
96
+ const viewportEl = document.createElement('div')
97
+ viewportEl.setAttribute('data-map-keyboard-scope', '')
98
+ container.appendChild(viewportEl)
99
+ appState.interfaceType = 'keyboard'
100
+
101
+ // interact starts disabled (e.g. a draw session already took over) — the crosshair
102
+ // is presumed to already be showing via that other owner, mirroring what
103
+ // DrawInit.jsx/drawInput.js would have set moments earlier.
104
+ renderHook(() => useCrossHairVisibility({ crossHair, enabled: false, selectMarkerOnly: false, appState }))
105
+ crossHair.fixAtCenter.mockClear()
106
+ crossHair.hide.mockClear()
107
+
108
+ // Focus moves into the map keyboard scope (e.g. draw's deferred focus-to-viewport
109
+ // after a menu selection) — interact must not call hide() here; it isn't the owner.
110
+ act(() => viewportEl.dispatchEvent(new FocusEvent('focusin', { bubbles: true })))
111
+ expect(crossHair.hide).not.toHaveBeenCalled()
112
+ expect(crossHair.fixAtCenter).not.toHaveBeenCalled()
113
+ })
114
+
115
+ it('does not show the crosshair for a menu-button Escape that never enters the map keyboard scope', () => {
116
+ const container = appState.layoutRefs.appContainerRef.current
117
+ const menuButton = document.createElement('button')
118
+ container.appendChild(menuButton)
119
+ appState.interfaceType = 'mouse'
120
+
121
+ const { rerender } = renderHook(
122
+ (props) => useCrossHairVisibility(props),
123
+ { initialProps: { crossHair, enabled: true, selectMarkerOnly: false, appState } }
124
+ )
125
+ expect(crossHair.hide).toHaveBeenCalled()
126
+
127
+ // Menu opened by mouse, focus lands on it, then Escape closes it and
128
+ // returns focus to the instigating button — interfaceType flips to
129
+ // 'keyboard' along the way, but the map keyboard scope was never entered.
130
+ act(() => menuButton.dispatchEvent(new FocusEvent('focusin', { bubbles: true })))
131
+ appState = { ...appState, interfaceType: 'keyboard' }
132
+ rerender({ crossHair, enabled: true, selectMarkerOnly: false, appState })
133
+
134
+ expect(crossHair.fixAtCenter).not.toHaveBeenCalled()
135
+ })
49
136
  })
@@ -1,14 +1,19 @@
1
1
  import { useEffect, useMemo } from 'react'
2
2
  import { buildStylesMap } from '../utils/buildStylesMap.js'
3
3
 
4
+ // How long after a map style/size change to keep re-applying highlights on every
5
+ // MAP_DATA_CHANGE — see the effect's own comment.
6
+ const SETTLE_WINDOW_MS = 3000
7
+
4
8
  /**
5
9
  * Keeps map highlight rendering in sync with the current selection and keyboard-active item.
6
10
  *
7
11
  * Calls mapProvider.updateHighlightedFeatures whenever selectedFeatures or listboxActiveItem
8
12
  * changes, passing selected features (shown with the selection ring) and the active item
9
13
  * (shown with the keyboard cursor ring) as separate arguments so the provider can style them
10
- * differently. Also re-applies highlights after a map style reload, since highlight layers
11
- * are removed when the base style changes.
14
+ * differently. Also re-applies highlights after a map style reload or a map-size change,
15
+ * since both remove/rebuild highlight layers and/or leave a selected feature's own drawn
16
+ * symbol (colours, resolution) briefly stale until the draw plugin re-resolves it.
12
17
  */
13
18
  export const useHighlightSync = ({
14
19
  mapProvider,
@@ -43,19 +48,35 @@ export const useHighlightSync = ({
43
48
 
44
49
  updateHighlightedFeatures()
45
50
 
46
- // Re-apply after style reload — highlight layers are removed when style reloads.
47
- // MAP_STYLE_CHANGE fires as soon as the new style is ready, before any plugin has
48
- // re-added its layers, so we register a one-time MAP_DATA_CHANGE listener instead.
49
- // MAP_DATA_CHANGE is debounced and fires once all layer additions from every plugin
50
- // have settled, giving us a single well-timed trigger. Using once() avoids the
51
- // infinite loop a permanent listener would cause (layer moves re-trigger MAP_DATA_CHANGE).
52
- const handleStyleChange = () => {
53
- eventBus.once(events.MAP_DATA_CHANGE, updateHighlightedFeatures)
51
+ // MAP_STYLE_CHANGE/MAP_SET_SIZE fire before layers are re-added or symbols re-resolved, so
52
+ // this arms a "keep re-applying" window rather than reacting once MAP_DATA_CHANGE can
53
+ // fire more than once as things settle, and a single listen-once would miss the later,
54
+ // real update. A permanent listener isn't safe either, since updateHighlightedFeatures()
55
+ // itself can trigger further MAP_DATA_CHANGE events. Uses `on`/`off`, not `once` its
56
+ // returned wrapper can't be off()'d by this same handler reference.
57
+ let settleUntil = 0
58
+ let armed = false
59
+ const reapply = () => {
60
+ updateHighlightedFeatures()
61
+ if (Date.now() >= settleUntil) {
62
+ eventBus.off(events.MAP_DATA_CHANGE, reapply)
63
+ armed = false
64
+ }
65
+ }
66
+ const armSettleWindow = () => {
67
+ settleUntil = Date.now() + SETTLE_WINDOW_MS
68
+ if (!armed) {
69
+ armed = true
70
+ eventBus.on(events.MAP_DATA_CHANGE, reapply)
71
+ }
54
72
  }
55
- eventBus.on(events.MAP_STYLE_CHANGE, handleStyleChange)
73
+ eventBus.on(events.MAP_STYLE_CHANGE, armSettleWindow)
74
+ eventBus.on(events.MAP_SET_SIZE, armSettleWindow)
56
75
 
57
76
  return () => {
58
- eventBus.off(events.MAP_STYLE_CHANGE, handleStyleChange)
77
+ eventBus.off(events.MAP_STYLE_CHANGE, armSettleWindow)
78
+ eventBus.off(events.MAP_SET_SIZE, armSettleWindow)
79
+ eventBus.off(events.MAP_DATA_CHANGE, reapply)
59
80
  }
60
81
  }, [selectedFeatures, listboxActiveItem, mapProvider, stylesMap, eventBus])
61
82
  }
@@ -7,19 +7,37 @@ jest.mock('../utils/buildStylesMap.js', () => ({
7
7
  }))
8
8
 
9
9
  const STYLE_CHANGE = 'map:stylechange'
10
+ const SET_SIZE = 'map:setsize'
10
11
  const DATA_CHANGE = 'map:datachange'
11
12
 
13
+ // A minimal real-ish event bus (mirrors src/services/eventBus.js's on/once/off contract)
14
+ // rather than jest.fn() stubs — the re-arming logic under test depends on once() genuinely
15
+ // self-removing and on() genuinely supporting multiple independent listeners, which a bare
16
+ // mock can't exercise faithfully.
17
+ const createEventBus = () => {
18
+ const listeners = {}
19
+ return {
20
+ on: jest.fn((event, handler) => { (listeners[event] ??= []).push(handler) }),
21
+ once: jest.fn((event, handler) => {
22
+ const wrapper = (...args) => { bus.off(event, wrapper); handler(...args) }
23
+ listeners[event] ??= []
24
+ listeners[event].push(wrapper)
25
+ }),
26
+ off: jest.fn((event, handler) => { listeners[event] = (listeners[event] ?? []).filter(h => h !== handler) }),
27
+ emit: (event, ...args) => { (listeners[event] ?? []).slice().forEach(h => h(...args)) },
28
+ _listenerCount: (event) => (listeners[event] ?? []).length
29
+ }
30
+ }
31
+ let bus
32
+
12
33
  let mockDeps
13
- let capturedStyleChangeHandler
14
- let capturedDataChangeHandler
15
34
 
16
35
  const render = (overrides = {}) =>
17
36
  renderHook(() => useHighlightSync({ ...mockDeps, ...overrides }))
18
37
 
19
38
  beforeEach(() => {
20
39
  jest.clearAllMocks()
21
- capturedStyleChangeHandler = null
22
- capturedDataChangeHandler = null
40
+ bus = createEventBus()
23
41
 
24
42
  mockDeps = {
25
43
  mapProvider: {
@@ -30,20 +48,8 @@ beforeEach(() => {
30
48
  layers: [{ layerId: 'layer1' }]
31
49
  },
32
50
  selectedFeatures: [],
33
- events: { MAP_STYLE_CHANGE: STYLE_CHANGE, MAP_DATA_CHANGE: DATA_CHANGE },
34
- eventBus: {
35
- on: jest.fn((event, handler) => {
36
- if (event === STYLE_CHANGE) {
37
- capturedStyleChangeHandler = handler
38
- }
39
- }),
40
- once: jest.fn((event, handler) => {
41
- if (event === DATA_CHANGE) {
42
- capturedDataChangeHandler = handler
43
- }
44
- }),
45
- off: jest.fn()
46
- }
51
+ events: { MAP_STYLE_CHANGE: STYLE_CHANGE, MAP_SET_SIZE: SET_SIZE, MAP_DATA_CHANGE: DATA_CHANGE },
52
+ eventBus: bus
47
53
  }
48
54
  })
49
55
 
@@ -95,28 +101,93 @@ describe('useHighlightSync — styles memoization', () => {
95
101
  })
96
102
  })
97
103
 
98
- // ─── useHighlightSync — style-change event ───────────────────────────────────
104
+ // ─── useHighlightSync — style/size-change settle window ──────────────────────
99
105
 
100
- describe('useHighlightSync — style-change event', () => {
106
+ describe('useHighlightSync — style/size-change settle window', () => {
101
107
  it('refreshes highlights after MAP_STYLE_CHANGE then MAP_DATA_CHANGE', () => {
102
108
  mockDeps.selectedFeatures = [{ featureId: 'F1', layerId: 'layer1' }]
103
109
 
104
110
  render()
105
111
  mockDeps.mapProvider.updateHighlightedFeatures.mockClear()
106
112
 
107
- act(() => capturedStyleChangeHandler())
108
- act(() => capturedDataChangeHandler())
113
+ act(() => bus.emit(STYLE_CHANGE))
114
+ act(() => bus.emit(DATA_CHANGE))
115
+
116
+ expect(mockDeps.mapProvider.updateHighlightedFeatures).toHaveBeenCalledTimes(1)
117
+ })
118
+
119
+ it('also refreshes after MAP_SET_SIZE then MAP_DATA_CHANGE', () => {
120
+ mockDeps.selectedFeatures = [{ featureId: 'F1', layerId: 'layer1' }]
121
+
122
+ render()
123
+ mockDeps.mapProvider.updateHighlightedFeatures.mockClear()
124
+
125
+ act(() => bus.emit(SET_SIZE))
126
+ act(() => bus.emit(DATA_CHANGE))
127
+
128
+ expect(mockDeps.mapProvider.updateHighlightedFeatures).toHaveBeenCalledTimes(1)
129
+ })
130
+
131
+ // The whole reason for re-arming rather than a single listen-once: MAP_DATA_CHANGE
132
+ // typically fires more than once during a settle (basemap loading before a drawn
133
+ // feature's own symbol re-resolution has finished) — the second, later firing must
134
+ // still be caught, not missed because the first already consumed a one-shot listener.
135
+ it('keeps re-applying on every MAP_DATA_CHANGE within the settle window, not just the first', () => {
136
+ mockDeps.selectedFeatures = [{ featureId: 'F1', layerId: 'layer1' }]
137
+
138
+ render()
139
+ mockDeps.mapProvider.updateHighlightedFeatures.mockClear()
140
+
141
+ act(() => bus.emit(STYLE_CHANGE))
142
+ act(() => bus.emit(DATA_CHANGE)) // early, still-stale settle
143
+ act(() => bus.emit(DATA_CHANGE)) // later, real settle
144
+ act(() => bus.emit(DATA_CHANGE))
145
+
146
+ expect(mockDeps.mapProvider.updateHighlightedFeatures).toHaveBeenCalledTimes(3)
147
+ })
148
+
149
+ it('stops re-arming once the settle window has elapsed, so it does not listen forever', () => {
150
+ jest.useFakeTimers()
151
+ mockDeps.selectedFeatures = [{ featureId: 'F1', layerId: 'layer1' }]
152
+
153
+ render()
154
+ mockDeps.mapProvider.updateHighlightedFeatures.mockClear()
155
+
156
+ act(() => bus.emit(STYLE_CHANGE))
157
+ act(() => bus.emit(DATA_CHANGE)) // re-arms — within the window
158
+ expect(bus._listenerCount(DATA_CHANGE)).toBe(1)
159
+
160
+ jest.advanceTimersByTime(4000) // past the settle window
161
+ act(() => bus.emit(DATA_CHANGE)) // the last re-arm still fires once...
162
+ expect(bus._listenerCount(DATA_CHANGE)).toBe(0) // ...but does not re-arm again
163
+
164
+ jest.useRealTimers()
165
+ })
166
+
167
+ it('a second style/size change while still settling extends the window without double-registering', () => {
168
+ jest.useFakeTimers()
169
+ mockDeps.selectedFeatures = [{ featureId: 'F1', layerId: 'layer1' }]
170
+
171
+ render()
172
+
173
+ act(() => bus.emit(STYLE_CHANGE))
174
+ expect(bus._listenerCount(DATA_CHANGE)).toBe(1)
175
+ act(() => bus.emit(SET_SIZE)) // still armed — must not add a second listener
176
+ expect(bus._listenerCount(DATA_CHANGE)).toBe(1)
109
177
 
110
- expect(mockDeps.mapProvider.updateHighlightedFeatures).toHaveBeenCalled()
178
+ jest.useRealTimers()
111
179
  })
112
180
 
113
- it('unsubscribes on unmount', () => {
181
+ it('unsubscribes MAP_STYLE_CHANGE/MAP_SET_SIZE/MAP_DATA_CHANGE listeners on unmount', () => {
114
182
  mockDeps.selectedFeatures = [{ featureId: 'F1', layerId: 'layer1' }]
115
183
 
116
184
  const { unmount } = render()
185
+ act(() => bus.emit(STYLE_CHANGE)) // arm the MAP_DATA_CHANGE re-apply listener too
117
186
  unmount()
118
187
 
119
- expect(mockDeps.eventBus.off).toHaveBeenCalledWith(STYLE_CHANGE, expect.any(Function))
188
+ expect(bus._listenerCount(STYLE_CHANGE)).toBe(0)
189
+ expect(bus._listenerCount(SET_SIZE)).toBe(0)
190
+ expect(bus._listenerCount(DATA_CHANGE)).toBe(0)
120
191
  })
121
192
  })
122
193
 
@@ -1,7 +1,25 @@
1
+ // mapbox-gl-draw (MapLibre only) splits every layer into a `.cold`/`.hot` sibling pair — see
2
+ // providers/maplibre/src/utils/drawLayerBuckets.js. Inlined here (not imported) since this file
3
+ // stays provider-agnostic and OpenLayers has no such split.
4
+ const drawBucketSiblingSuffix = { '.cold': '.hot', '.hot': '.cold' }
5
+
6
+ const siblingLayerId = (layerId) => {
7
+ for (const [suffix, sibling] of Object.entries(drawBucketSiblingSuffix)) {
8
+ if (layerId.endsWith(suffix)) {
9
+ return `${layerId.slice(0, -suffix.length)}${sibling}`
10
+ }
11
+ }
12
+ return null
13
+ }
14
+
1
15
  export const buildLayerConfigMap = dataLayers => {
2
16
  const map = {}
3
17
  for (const layer of dataLayers) {
4
18
  map[layer.layerId] = layer
19
+ const sibling = siblingLayerId(layer.layerId)
20
+ if (sibling) {
21
+ map[sibling] = layer
22
+ }
5
23
  }
6
24
  return map
7
25
  }
@@ -15,6 +15,21 @@ describe('buildLayerConfigMap', () => {
15
15
 
16
16
  expect(buildLayerConfigMap([])).toEqual({})
17
17
  })
18
+
19
+ // mapbox-gl-draw (MapLibre only) moves a feature out of its `.cold` layer/source into a
20
+ // `.hot` sibling the instant any of its own properties change — a click landing on a feature
21
+ // that's since moved would otherwise silently fail to match any registered config at all.
22
+ it('also registers the .cold/.hot sibling id, pointing at the same config', () => {
23
+ const dataLayers = [{ layerId: 'point-symbol.cold', idProperty: 'id' }]
24
+ const result = buildLayerConfigMap(dataLayers)
25
+ expect(result['point-symbol.cold']).toBe(result['point-symbol.hot'])
26
+ expect(result['point-symbol.hot']).toEqual({ layerId: 'point-symbol.cold', idProperty: 'id' })
27
+ })
28
+
29
+ it('does not add a sibling for a layer id with no cold/hot suffix', () => {
30
+ const result = buildLayerConfigMap([{ layerId: 'field-parcels' }])
31
+ expect(Object.keys(result)).toEqual(['field-parcels'])
32
+ })
18
33
  })
19
34
 
20
35
  describe('getFeaturesAtPoint', () => {
@@ -41,19 +41,25 @@ function isContiguousWithAny (feature, features) {
41
41
  return features.some(f => !booleanDisjoint(toTurfGeometry(f), toTurfGeometry(feature)))
42
42
  }
43
43
 
44
+ const isPolygonal = (type) => type === 'Polygon' || type === 'MultiPolygon'
45
+
44
46
  /**
45
- * Check if all features form a single contiguous group (can be merged).
47
+ * Check if all features are polygons/multi-polygons and form a single contiguous group
48
+ * (mergeable). Mixed geometry types (e.g. a line crossing a polygon) are never contiguous,
49
+ * regardless of spatial overlap, so the type check runs first and skips the spatial work
50
+ * entirely when it fails.
51
+ *
46
52
  * Uses flood-fill to find connected components.
47
53
  *
48
54
  * @param {Array} features - Array of features to test
49
- * @returns {boolean} True if 2+ features and all are contiguous
55
+ * @returns {boolean} True if 2+ features, all polygonal, and all contiguous
50
56
  */
51
57
  function areAllContiguous (features) {
52
58
  if (features.length < 2) {
53
59
  return false
54
60
  }
55
61
 
56
- if (features.some(f => !f.geometry?.type)) {
62
+ if (features.some(feature => !isPolygonal(feature.geometry?.type))) {
57
63
  return false
58
64
  }
59
65
 
@@ -67,9 +67,11 @@ describe('areAllContiguous', () => {
67
67
  const B = poly([[2, 0], [4, 0], [4, 2], [2, 2], [2, 0]]) // touches A
68
68
  const C = poly([[4, 0], [6, 0], [6, 2], [4, 2], [4, 0]]) // touches B
69
69
  const D = poly([[10, 10], [12, 10], [12, 12], [10, 12], [10, 10]]) // isolated
70
+ const multiA = { geometry: { type: 'MultiPolygon', coordinates: [[[[0, 0], [2, 0], [2, 2], [0, 2], [0, 0]]]] } } // same shape as A
70
71
 
71
72
  const noGeom = { geometry: undefined }
72
73
  const noType = { geometry: {} }
74
+ const lineThroughA = { geometry: { type: 'LineString', coordinates: [[1, -1], [1, 3]] } } // crosses straight through A's interior
73
75
 
74
76
  it.each([
75
77
  [[], false],
@@ -81,8 +83,17 @@ describe('areAllContiguous', () => {
81
83
  [[noGeom, A], false],
82
84
  [[A, noGeom], false],
83
85
  [[noGeom, noGeom], false],
84
- [[noType, A], false]
86
+ [[noType, A], false],
87
+ [[multiA, B], true],
88
+ [[A, lineThroughA], false]
85
89
  ])('returns expected result for %# features', (features, expected) => {
86
90
  expect(areAllContiguous(features)).toBe(expected)
87
91
  })
92
+
93
+ it('excludes a line from the contiguous group even when it spatially crosses a polygon', () => {
94
+ // Without the type restriction this would be true — isContiguousWithAny alone treats
95
+ // a line crossing a polygon's interior the same as a shared boundary.
96
+ expect(isContiguousWithAny(lineThroughA, [A])).toBe(true)
97
+ expect(areAllContiguous([A, lineThroughA])).toBe(false)
98
+ })
88
99
  })
@@ -0,0 +1,62 @@
1
+ .im-c-map-key > *:first-child {
2
+ padding-top: 5px;
3
+ }
4
+ .im-c-map-key > *:first-child .im-c-map-key__group-heading {
5
+ padding-top: 0;
6
+ }
7
+
8
+ .im-c-map-key--has-groups > *:not(:first-child) {
9
+ border-top: 1px solid var(--button-hover-color);
10
+ }
11
+
12
+ .im-c-map-key__group:not(:last-child) {
13
+ padding-bottom: 5px;
14
+ }
15
+
16
+ .im-c-map-key__group-heading {
17
+ padding-top: 15px;
18
+ padding-bottom: 10px;
19
+ margin: 0;
20
+ font-size: 1rem;
21
+ font-weight: bold;
22
+ color: var(--foreground-color);
23
+ }
24
+
25
+ .im-c-map-key__item {
26
+ display: flex;
27
+ align-items: start;
28
+ padding-top: 10px;
29
+ padding-bottom: 10px;
30
+ font-size: 1rem;
31
+ }
32
+ .im-c-map-key__group .im-c-map-key__item:first-child {
33
+ padding-top: 0;
34
+ }
35
+
36
+ .im-c-map-key--has-groups > .im-c-map-key__item:not(:first-child) {
37
+ padding-top: 15px;
38
+ }
39
+
40
+ .im-c-map-key--has-groups > .im-c-map-key__item {
41
+ padding-bottom: 15px;
42
+ }
43
+
44
+ .im-c-map-key__group .im-c-map-key__item {
45
+ padding-top: 10px;
46
+ padding-bottom: 10px;
47
+ }
48
+
49
+ .im-c-map-key > .im-c-map-key__item:last-child,
50
+ .im-c-map-key__group:last-child .im-c-map-key__item:last-child {
51
+ padding-bottom: 5px;
52
+ }
53
+
54
+ .am-c-map-key-symbol {
55
+ position: relative;
56
+ flex-shrink: 0;
57
+ margin: 0 13px 0 3px;
58
+ }
59
+
60
+ .am-c-map-key-symbol--point {
61
+ margin: -12px 1px -12px -9px;
62
+ }
@@ -0,0 +1 @@
1
+ import{useState as e,useEffect as t}from"preact/compat";import{jsx as r,jsxs as o}from"preact/jsx-runtime";import n from"@babel/runtime/helpers/defineProperty";import l from"@babel/runtime/helpers/asyncToGenerator";var a=null,i=e=>a=e,c={"cross-hatch":'<path d="M0 4.486V3.485h3.5V.001h1v3.484h7.002V.001h1v3.484h3.5v1.001h-3.5v7h3.5v.999h-3.5v3.516h-1v-3.516H4.499v3.516h-1v-3.516H0v-.999h3.5v-7H0zm11.501 0H4.499v7h7.002v-7z" fill="{{foregroundColor}}"/>',"diagonal-cross-hatch":'<path d="M0 8.707V7.293L7.293 0h1.414L16 7.293v1.414L8.707 16H7.293L0 8.707zM.707 8L8 15.293 15.293 8 8 .707.707 8z" fill="{{foregroundColor}}"/>',"forward-diagonal-hatch":'<path d="M16 8.707V7.293L7.293 16h1.414L16 8.707zm-16 0L8.707 0H7.293L0 7.293v1.414z" fill="{{foregroundColor}}"/>',"backward-diagonal-hatch":'<path d="M0 8.707V7.293L8.707 16H7.293L0 8.707zm16 0L7.293 0h1.414L16 7.293v1.414z" fill="{{foregroundColor}}"/>',"horizontal-hatch":'<path d="M0 4.5V3.499h15.999V4.5H0zm0 7h15.999V12.5H0v-1.001z" fill="{{foregroundColor}}"/>',"vertical-hatch":'<path d="M3.501 16.001V0h1v16.001h-1zm7.998 0V0h1v16.001h-1z" fill="{{foregroundColor}}"/>',dot:'<path d="M3.999 2A2 2 0 0 1 6 3.999C6 5.103 5.103 6 3.999 6a2 2 0 0 1-1.999-2.001A2 2 0 0 1 3.999 2zm0 7.999C5.103 10 6 10.897 6 12.001A2 2 0 0 1 3.999 14a2 2 0 0 1-1.999-1.999A2 2 0 0 1 3.999 10zM11.999 2A2 2 0 0 1 14 3.999C14 5.103 13.103 6 11.999 6S10 5.103 10 3.999A2 2 0 0 1 11.999 2zm0 7.999c1.104 0 2.001.897 2.001 2.001A2 2 0 0 1 11.999 14 2 2 0 0 1 10 12.001c0-1.104.897-2.001 1.999-2.001z" fill="{{foregroundColor}}"/>',diamond:'<path d="M4 .465L7.535 4 4 7.535.465 4 4 .465zm0 7.999l3.535 3.535L4 15.535.465 11.999 4 8.464zm8-8l3.535 3.535-3.536 3.536L8.464 4 12 .464zm0 8.001L15.536 12 12 15.536 8.465 12 12 8.465z" fill="{{foregroundColor}}"/>'},s=(e,t)=>{if(!e)return null;if("string"==typeof e)return e.trim();if("object"==typeof e){if(t&&e[t])return e[t];var r=Object.values(e)[0];return null!=r?r:null}return null},f=(e,t,r)=>e.replace(/\{\{foregroundColor\}\}/g,t||"black").replace(/\{\{backgroundColor\}\}/g,r),p=new Map,d={register(e,t){p.set(e,{id:e,svgContent:t})},get:e=>p.get(e),list:()=>[...p.values()],clear(){p.clear()},initialise(){Object.entries(c).forEach(e=>{var[t,r]=e;this.register(t,r)})},getPatternInnerContent(e){return e.fillPatternSvgContent?e.fillPatternSvgContent:e.fillPattern&&null!==(t=null===(r=this.get(e.fillPattern))||void 0===r?void 0:r.svgContent)&&void 0!==t?t:null;var t,r},getKeyPatternPaths(e,t){var r=this.getPatternInnerContent(e);if(!r)return null;var o=s(e.fillPatternForegroundColor,t)||"black",n=s(e.fillPatternBackgroundColor,t)||"transparent",l=s(e.stroke,t)||o;return{border:f('<path d="M19 2.862v14.275c0 1.028-.835 1.862-1.862 1.862H2.863c-1.028 0-1.862-.835-1.862-1.862V2.862C1.001 1.834 1.836 1 2.863 1h14.275C18.166 1 19 1.835 19 2.862z" fill="{{backgroundColor}}" stroke="{{foregroundColor}}" stroke-width="2"/>',l,n),content:f(r,o,n)}},getPatternImageId(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1,o=this.getPatternInnerContent(e);if(!o)return null;var n=s(e.fillPatternForegroundColor,t)||"black",l=s(e.fillPatternBackgroundColor,t)||"transparent",a=(e=>Math.max(2,2*e))(r);return"pattern-".concat((e=>{var t=0;for(var r of e)t=Math.trunc((t<<5)-t+r.codePointAt(0));return Math.abs(t).toString(36)})(o+n+l),"-").concat(a,"x")}};d.initialise();var u={symbol:"pin",backgroundColor:"#ca3535",foregroundColor:"#ffffff"},h={dot:"M8 3c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.241 5-5-2.24-5-5-5z",cross:"M6 3H10V6H13V10H10V13H6V10H3V6H6Z",diamond:"M8 2L14 8L8 14L2 8Z",triangle:"M8 2L14 14H2Z",square:"M3 3H13V13H3Z"},v={id:"pin",viewBox:"0 0 44 44",anchor:[.5,.9],graphic:h.dot,svg:'<path d="M22 40.999c-3.621 0-8.306-5.864-10.258-8.3C9.02 29.302 6 23.66 6 19.002a16.01 16.01 0 0 1 16-16 16.01 16.01 0 0 1 16 16c0 4.658-3.02 10.3-5.742 13.697-1.952 2.437-6.637 8.3-10.258 8.3z" fill="{{selectedColor}}" stroke="{{activeColor}}" stroke-width="6" paint-order="stroke fill"/>\n <path d="M22 7.001a12.01 12.01 0 0 1 12 12c0 7.623-10.377 17.998-12 17.998S10 26.624 10 19.001a12.01 12.01 0 0 1 12-12z" fill="{{backgroundColor}}" stroke="{{haloColor}}" stroke-width="2" paint-order="stroke fill"/>\n <g transform="translate(22, 19) scale(0.8) translate(-8, -8)"><path d="{{graphic}}" fill="{{foregroundColor}}"/></g>'},g={id:"circle",viewBox:"0 0 44 44",anchor:[.5,.5],graphic:h.dot,svg:'<circle cx="22" cy="22" r="16" fill="{{selectedColor}}" stroke="{{activeColor}}" stroke-width="6" paint-order="stroke fill"/>\n <circle cx="22" cy="22" r="12" fill="{{backgroundColor}}" stroke="{{haloColor}}" stroke-width="2" paint-order="stroke fill"/>\n <g transform="translate(22, 22) scale(0.8) translate(-8, -8)"><path d="{{graphic}}" fill="{{foregroundColor}}"/></g>'},m={id:"square",viewBox:"0 0 44 44",anchor:[.5,.5],graphic:h.dot,svg:'<path d="M13 6h18c3.863 0 7 3.137 7 7v18c0 3.863-3.137 7-7 7H13c-3.863 0-7-3.137-7-7V13c0-3.863 3.137-7 7-7" fill="{{selectedColor}}" stroke="{{activeColor}}" stroke-width="6" paint-order="stroke fill"/>\n <path d="M13 34a3 3 0 0 1-3-3V13a3 3 0 0 1 3-3h18a3 3 0 0 1 3 3v18a3 3 0 0 1-3 3H13z" fill-rule="nonzero" fill="{{backgroundColor}}" stroke="{{haloColor}}" stroke-width="2" paint-order="stroke fill"/>\n <g transform="translate(22, 22) scale(0.8) translate(-8, -8)"><path d="{{graphic}}" fill="{{foregroundColor}}"/></g>'},y=new Set(["symbolBackgroundColor","symbolForegroundColor","symbolHaloWidth","symbolGraphic"]),b=e=>{if(!(e=>!(!e.symbol&&!e.symbolSvgContent))(e))return{};var t={};return y.forEach(r=>{if(null!=e[r]){var o=r.charAt(6).toLowerCase()+r.slice(7);t[o]=e[r]}}),t},O=(e,t)=>{var r;return e.symbolViewBox?e.symbolViewBox:null!==(r=null==t?void 0:t.viewBox)&&void 0!==r?r:"0 0 38 38"},k={light:{haloColor:"#ffffff",selectedColor:"#0b0c0c",activeColor:"#ffdd00",foregroundColor:"#0b0c0c"},dark:{haloColor:"#0b0c0c",selectedColor:"#ffffff",activeColor:"#ffdd00",foregroundColor:"#ffffff"}};function w(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,o)}return r}function C(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?w(Object(r),!0).forEach(function(t){n(e,t,r[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):w(Object(r)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})}return e}var j=new Map,P=new Map,S={},D=e=>{var t=0;for(var r of e)t=Math.trunc((t<<5)-t+r.codePointAt(0));return Math.abs(t).toString(36)},M=new Set(["id","svg","viewBox","anchor","symbol","symbolSvgContent"]);function x(e,t,r){var o,n,l,a,i=null==r?void 0:r.id,c=Object.fromEntries(Object.entries(e||{}).filter(e=>{var[t]=e;return!M.has(t)})),f=Object.fromEntries(Object.entries(S).filter(e=>{var[t]=e;return!M.has(t)})),p=Object.fromEntries(Object.entries(t).filter(e=>{var[,t]=e;return null!=t})),d=C(C(C(C({},u),f),c),p),v=null!==(o=k[null==r?void 0:r.mapColorScheme])&&void 0!==o?o:k.light;return d.haloColor=null!==(n=null==r?void 0:r.haloColor)&&void 0!==n?n:v.haloColor,d.selectedColor=null!==(l=null==r?void 0:r.selectedColor)&&void 0!==l?l:v.selectedColor,d.activeColor=null!==(a=null==r?void 0:r.activeColor)&&void 0!==a?a:v.activeColor,"string"==typeof d.graphic&&h[d.graphic]&&(d.graphic=h[d.graphic]),Object.fromEntries(Object.entries(d).map(e=>{var[t,r]=e;return[t,s(r,i)||""]}))}function L(e,t){return Object.entries(t).reduce((e,t)=>{var[r,o]=t;return e.replaceAll("{{".concat(r,"}}"),o)},e)}var z={setDefaults(e){S=e||{}},getDefaults:()=>C(C({},u),S),register(e){j.set(e.id,e)},get:e=>j.get(e),list:()=>[...j.values()],clear(){j.clear()},initialise(){this.register(v),this.register(g),this.register(m)},resolve(e,t,r){var o=x(e,t||{},r);return e?(o.selectedColor="none",o.activeColor="none",L(e.svg,o)):""},resolveActive(e,t,r){var o=x(e,t||{},r);return e?L(e.svg,o):""},resolveSelected(e,t,r){var o=x(e,t||{},r);return e?(o.activeColor="none",L(e.svg,o)):""},getSymbolImageId(e,t){var r=arguments.length>2&&void 0!==arguments[2]&&arguments[2],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:2,n=this.getSymbolDef(e);if(!n)return null;var l=b(e),a=r?this.resolveActive(n,l,t):this.resolve(n,l,t);return"symbol-".concat(r?"act-":"").concat(D(a),"-").concat(o,"x")},getSymbolDef(e){return e.symbolSvgContent?{svg:e.symbolSvgContent}:e.symbol?this.get(e.symbol):void 0},rasteriseSymbolImage(e,t,r,o){var n=this;return l(function*(){var l=n.getSymbolDef(e);if(!l)return null;var a,i,c=b(e);"active"===r?(a=n.resolveActive(l,c,t),i="act-"):"selected"===r?(a=n.resolveSelected(l,c,t),i="sel-"):(a=n.resolve(l,c,t),i="");var s="symbol-".concat(i).concat(D(a),"-").concat(o,"x"),f=P.get(s);if(!f){var p=O(e,l),[,,d,u]=p.split(" ").map(Number),h='<svg xmlns="http://www.w3.org/2000/svg" width="'.concat(d*o,'" height="').concat(u*o,'" viewBox="').concat(p,'">').concat(a,"</svg>");f=yield((e,t,r)=>new Promise((o,n)=>{var l="data:image/svg+xml;charset=utf-8,".concat(encodeURIComponent(e)),a=new Image(t,r);a.onload=()=>{var e=document.createElement("canvas");e.width=t,e.height=r;var n=e.getContext("2d");n.drawImage(a,0,0,t,r),o(n.getImageData(0,0,t,r))},a.onerror=()=>{n(new Error("Failed to rasterise SVG: ".concat(e.slice(0,80))))},a.src=l}))(h,d*o,u*o),P.set(s,f)}return{imageId:s,imageData:f}})()}};z.initialise();var I=e=>{var{text:t}=e;return r("div",{className:"im-c-map-key",children:r("p",{className:"im-c-map-key__empty-message",children:t})})};function H(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,o)}return r}function V(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?H(Object(r),!0).forEach(function(t){n(e,t,r[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):H(Object(r)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})}return e}var E=20,_={xmlns:"http://www.w3.org/2000/svg",width:E,height:E,viewBox:"0 0 ".concat(E," ").concat(E),className:"am-c-map-key-symbol","aria-hidden":"true",focusable:"false"},B=V(V({},_),{},{width:44,height:44,className:"am-c-map-key-symbol am-c-map-key-symbol--point"});function A(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,o)}return r}function N(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?A(Object(r),!0).forEach(function(t){n(e,t,r[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):A(Object(r)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})}return e}var K=n=>{var{keyDefinition:l,mapStyle:a}=n,[i,c]=e(null);return t(()=>{var{style:e}=l;c(d.getKeyPatternPaths(e,a.id))},[a.id,l]),i?o("svg",N(N({},_),{},{children:[r("g",{dangerouslySetInnerHTML:{__html:i.border}}),r("g",{transform:"translate(".concat(2,", ").concat(2,")"),dangerouslySetInnerHTML:{__html:i.content}})]})):null};function G(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,o)}return r}function T(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?G(Object(r),!0).forEach(function(t){n(e,t,r[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):G(Object(r)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})}return e}var W=o=>{var{keyDefinition:n,mapStyle:l,symbolDef:a}=o,[i,c]=e(null),[s,f]=e(null);return t(()=>{var e,{style:t}=n,r=null!==(e=null==l?void 0:l.appColorScheme)&&void 0!==e?e:"light",o=T(T({},l),{},{mapColorScheme:r});c(z.resolve(a,b(t),o)),f(O(t,a))},[l,n]),i&&s?r("svg",T(T({},B),{},{viewBox:s,children:r("g",{dangerouslySetInnerHTML:{__html:i}})})):null};function q(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,o)}return r}function F(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?q(Object(r),!0).forEach(function(t){n(e,t,r[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):q(Object(r)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})}return e}var Z=o=>{var{mapStyle:n,keyDefinition:l}=o,[a,i]=e(2),[c,f]=e("#ff0000");return t(()=>{var{style:e}=l;i(e.strokeWidth),f(s(e.stroke,n.id))},[n.id,l]),r("svg",F(F({},_),{},{children:r("line",{x1:a/2,y1:10,x2:E-a/2,y2:10,stroke:c,strokeWidth:a,strokeLinecap:"round"})}))};function R(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,o)}return r}function U(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?R(Object(r),!0).forEach(function(t){n(e,t,r[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):R(Object(r)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})}return e}var J=o=>{var{mapStyle:n,keyDefinition:l}=o,[a,i]=e(2),[c,f]=e("#ff0000"),[p,d]=e("#ff0000");return t(()=>{var{style:e}=l;i(e.strokeWidth),f(s(e.fill,n.id)),d(s(e.stroke,n.id))},[n.id,l]),r("svg",U(U({},_),{},{children:r("rect",{x:a/2,y:a/2,width:E-a,height:E-a,rx:a,ry:a,fill:c,stroke:p,strokeWidth:a,strokeLinejoin:"round"})}))},Q=o=>{var{keyDefinition:n,mapStyle:l}=o,[a,i]=e(null),[c,s]=e(null);return t(()=>{if(n){var{hasSymbol:e,hasPattern:t,style:r}=n;if(e){var o=z.getSymbolDef(r);s(o),i(o?"symbol":"rect")}else t?i("pattern"):"line"===r.keySymbolShape?i("line"):i("rect")}else i(null)},[n]),a?"symbol"===a?r(W,{mapStyle:l,keyDefinition:n,symbolDef:c}):r("pattern"===a?K:"line"===a?Z:J,{mapStyle:l,keyDefinition:n}):null},X=n=>{var{keyDefinition:l,mapStyle:a}=n,[i,c]=e(""),[f,p]=e("");return t(()=>{c(l.label),p(s(l.symbolDescription,a.id))},[l,a.id]),o("dl",{className:"im-c-map-key__item",children:[r("dt",{className:"im-c-map-key__item-symbol",children:r(Q,{keyDefinition:l,mapStyle:a})}),o("dd",{className:"im-c-map-key__item-label",children:[i,f&&o("span",{className:"govuk-visually-hidden",children:["(",f,")"]})]})]})},Y=e=>{var{headingId:t,label:n,keyDefinitions:l,mapStyle:a}=e;return o("section",{className:"im-c-map-key__group","aria-labelledby":t,children:[r("h3",{id:t,className:"im-c-map-key__group-heading",children:n}),l.map(e=>r(X,{keyDefinition:e,mapStyle:a},"".concat(e.id)))]})},$="im-c-map-key",ee=e=>{var{item:t,mapStyle:o}=e;return"group"===t.type?r(Y,{headingId:"key-heading-".concat(t.id),label:t.groupLabel,keyDefinitions:t.keyDefinitions,mapStyle:o}):r(X,{keyDefinition:t.keyDefinition,mapStyle:o})},te=o=>{var{noKeyItemText:n,keyGroups:l,hasGroups:a,mapStyle:i}=o;if(null==l||!l.length)return r(I,{text:n});var[c,s]=e("im-c-map-key");return t(()=>s(a?"".concat($," ").concat("im-c-map-key--has-groups"):$),[a]),r("div",{className:c,children:l.map(e=>r(ee,{item:e,mapStyle:i},e.id))})};var re={InitComponent:function(e){var{mapState:r,services:o}=e,{eventBus:n}=o;t(()=>{r.isMapReady&&n.requestOnce("datasets:registry",i)},[r.isMapReady])},panels:[{id:"mapKey",label:"Key",mobile:{slot:"drawer",modal:!0},tablet:{slot:"left-top",width:"260px"},desktop:{slot:"left-top",width:"280px"},render:function(o){var{mapState:{mapStyle:n},pluginConfig:{noKeyItemText:l},services:{eventBus:i}}=o,[c,s]=e([]),[f,p]=e(!1),[d,u]=e(a),h=()=>{var{items:e,hasGroups:t}=d.keyItems();s(e),p(t)},v=e=>{d.invalidateKeyItemsOnMenuStateChange(e),h()};return t(()=>d?(h(),i.on("menu:changed",v).on("datasets:changed",h),()=>i.off("menu:changed",v).off("datasets:changed",h)):(i.requestOnce("datasets:registry",u),()=>{}),[d]),r(te,{noKeyItemText:l,keyGroups:c,hasGroups:f,mapStyle:n})}}],buttons:[{id:"mapKey",panelId:"mapKey",label:"Key",iconId:"key",mobile:{slot:"top-left",showLabel:!1},tablet:{slot:"top-left",showLabel:!0},desktop:{slot:"top-left",showLabel:!0}}],icons:[{id:"key",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"/>'}]};export{re as manifest};
@@ -0,0 +1 @@
1
+ import e from"@babel/runtime/helpers/asyncToGenerator";import r from"@babel/runtime/helpers/defineProperty";function t(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter(function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable})),t.push.apply(t,n)}return t}function n(e){for(var n=1;n<arguments.length;n++){var o=null!=arguments[n]?arguments[n]:{};n%2?t(Object(o),!0).forEach(function(t){r(e,t,o[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(o)):t(Object(o)).forEach(function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(o,r))})}return e}function o(){var r;return n(n({noKeyItemText:"No features displayed"},arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),{},{id:"mapKey",load:(r=e(function*(){return(yield import(/* webpackChunkName: "im-map-key-plugin" */ "./im-map-key-plugin.js")).manifest}),function(){return r.apply(this,arguments)})})}export{o as default};