@defra/interactive-map 0.0.15-alpha → 0.0.17-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 (263) hide show
  1. package/assets/css/docusaurus.css +104 -0
  2. package/assets/images/favicon.svg +1 -0
  3. package/assets/images/hero.png +0 -0
  4. package/assets/images/slot-map.svg +264 -0
  5. package/dist/css/index.css +1 -1
  6. package/dist/esm/im-core.js +1 -1
  7. package/dist/esm/im-shell.js +1 -1
  8. package/dist/umd/im-core.js +1 -1
  9. package/dist/umd/index.js +1 -1
  10. package/docs/api/slots.md +90 -6
  11. package/docs/api.md +4 -4
  12. package/docs/architecture.md +3 -1
  13. package/docs/{demo.mdx → examples.mdx} +1 -1
  14. package/docs/getting-started.md +5 -4
  15. package/docs/index.mdx +42 -0
  16. package/docs/plugins/datasets.md +561 -0
  17. package/docs/plugins/interact.md +176 -55
  18. package/docs/plugins/map-styles.md +64 -7
  19. package/docs/plugins/search.md +207 -63
  20. package/docs/plugins.md +8 -16
  21. package/docusaurus.config.cjs +34 -34
  22. package/jest.setup.js +1 -1
  23. package/package.json +6 -5
  24. package/plugins/beta/datasets/dist/css/index.css +85 -15
  25. package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
  26. package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +1 -1
  27. package/plugins/beta/datasets/dist/umd/index.js +1 -1
  28. package/plugins/beta/datasets/src/DatasetsInit.jsx +24 -9
  29. package/plugins/beta/datasets/src/adapters/maplibre/index.js +18 -0
  30. package/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.js +113 -0
  31. package/plugins/beta/datasets/src/adapters/maplibre/layerIds.js +69 -0
  32. package/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js +338 -0
  33. package/plugins/beta/datasets/src/adapters/maplibre/patternRegistry.js +48 -0
  34. package/plugins/beta/datasets/src/api/addDataset.js +3 -9
  35. package/plugins/beta/datasets/src/api/getOpacity.js +17 -0
  36. package/plugins/beta/datasets/src/api/getStyle.js +13 -0
  37. package/plugins/beta/datasets/src/api/removeDataset.js +3 -45
  38. package/plugins/beta/datasets/src/api/setData.js +8 -0
  39. package/plugins/beta/datasets/src/api/setDatasetVisibility.js +37 -0
  40. package/plugins/beta/datasets/src/api/setFeatureVisibility.js +22 -0
  41. package/plugins/beta/datasets/src/api/setOpacity.js +29 -0
  42. package/plugins/beta/datasets/src/api/setStyle.js +22 -0
  43. package/plugins/beta/datasets/src/datasets.js +33 -59
  44. package/plugins/beta/datasets/src/defaults.js +43 -9
  45. package/plugins/beta/datasets/src/fetch/createDynamicSource.js +39 -30
  46. package/plugins/beta/datasets/src/fetch/fetchGeoJSON.js +2 -2
  47. package/plugins/beta/datasets/src/manifest.js +27 -19
  48. package/plugins/beta/datasets/src/panels/Key.jsx +129 -49
  49. package/plugins/beta/datasets/src/panels/Key.module.scss +48 -9
  50. package/plugins/beta/datasets/src/panels/Layers.jsx +131 -29
  51. package/plugins/beta/datasets/src/panels/Layers.module.scss +50 -8
  52. package/plugins/beta/datasets/src/reducer.js +128 -9
  53. package/plugins/beta/datasets/src/styles/patterns.js +157 -0
  54. package/plugins/beta/datasets/src/utils/bbox.js +8 -6
  55. package/plugins/beta/datasets/src/utils/filters.js +5 -2
  56. package/plugins/beta/datasets/src/utils/mergeSublayer.js +78 -0
  57. package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
  58. package/plugins/beta/draw-es/src/DrawInit.jsx +16 -16
  59. package/plugins/beta/draw-es/src/api/addFeature.js +3 -3
  60. package/plugins/beta/draw-es/src/api/deleteFeature.js +3 -3
  61. package/plugins/beta/draw-es/src/api/editFeature.js +3 -3
  62. package/plugins/beta/draw-es/src/api/newPolygon.js +3 -3
  63. package/plugins/beta/draw-es/src/events.js +52 -20
  64. package/plugins/beta/draw-es/src/events.test.js +301 -0
  65. package/plugins/beta/draw-es/src/graphic.js +1 -1
  66. package/plugins/beta/draw-es/src/manifest.js +4 -4
  67. package/plugins/beta/draw-es/src/reducer.js +1 -1
  68. package/plugins/beta/draw-es/src/sketchViewModel.js +1 -1
  69. package/plugins/beta/draw-ml/dist/css/index.css +1 -1
  70. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
  71. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
  72. package/plugins/beta/draw-ml/src/DrawInit.jsx +49 -52
  73. package/plugins/beta/draw-ml/src/api/deleteFeature.js +1 -1
  74. package/plugins/beta/draw-ml/src/api/editFeature.js +8 -5
  75. package/plugins/beta/draw-ml/src/api/newLine.js +0 -1
  76. package/plugins/beta/draw-ml/src/api/newPolygon.js +0 -1
  77. package/plugins/beta/draw-ml/src/api/split.js +4 -4
  78. package/plugins/beta/draw-ml/src/defaults.js +1 -1
  79. package/plugins/beta/draw-ml/src/draw.scss +0 -7
  80. package/plugins/beta/draw-ml/src/events.js +8 -6
  81. package/plugins/beta/draw-ml/src/manifest.js +29 -29
  82. package/plugins/beta/draw-ml/src/mapboxDraw.js +1 -1
  83. package/plugins/beta/draw-ml/src/mapboxSnap.js +17 -18
  84. package/plugins/beta/draw-ml/src/modes/createDrawMode.js +31 -31
  85. package/plugins/beta/draw-ml/src/modes/disabledMode.js +1 -1
  86. package/plugins/beta/draw-ml/src/modes/editVertex/touchHandlers.js +11 -11
  87. package/plugins/beta/draw-ml/src/modes/editVertex/undoHandlers.js +7 -7
  88. package/plugins/beta/draw-ml/src/modes/editVertex/vertexOperations.js +8 -8
  89. package/plugins/beta/draw-ml/src/modes/editVertex/vertexQueries.js +7 -7
  90. package/plugins/beta/draw-ml/src/modes/editVertexMode.js +32 -24
  91. package/plugins/beta/draw-ml/src/reducer.js +1 -1
  92. package/plugins/beta/draw-ml/src/undoStack.js +4 -4
  93. package/plugins/beta/draw-ml/src/utils/snapHelpers.js +12 -12
  94. package/plugins/beta/draw-ml/src/utils/spatial.js +11 -11
  95. package/plugins/beta/frame/dist/esm/im-frame-plugin.js +1 -1
  96. package/plugins/beta/frame/dist/umd/im-frame-plugin.js +1 -1
  97. package/plugins/beta/frame/src/Frame.jsx +9 -9
  98. package/plugins/beta/frame/src/FrameInit.jsx +4 -4
  99. package/plugins/beta/frame/src/api/addFrame.js +1 -1
  100. package/plugins/beta/frame/src/api/editFeature.js +1 -1
  101. package/plugins/beta/frame/src/config.js +1 -1
  102. package/plugins/beta/frame/src/manifest.js +3 -3
  103. package/plugins/beta/frame/src/reducer.js +1 -1
  104. package/plugins/beta/frame/src/utils.js +1 -1
  105. package/plugins/beta/map-styles/dist/esm/im-map-styles-plugin.js +1 -1
  106. package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -1
  107. package/plugins/beta/map-styles/src/MapStyles.jsx +18 -18
  108. package/plugins/beta/map-styles/src/manifest.js +1 -1
  109. package/plugins/beta/scale-bar/dist/css/index.css +1 -1
  110. package/plugins/beta/scale-bar/dist/esm/im-scale-bar-plugin.js +1 -1
  111. package/plugins/beta/scale-bar/dist/umd/im-scale-bar-plugin.js +1 -1
  112. package/plugins/beta/scale-bar/src/ScaleBar.jsx +5 -5
  113. package/plugins/beta/scale-bar/src/index.test.js +3 -3
  114. package/plugins/beta/scale-bar/src/manifest.js +3 -3
  115. package/plugins/beta/scale-bar/src/scaleBar.scss +2 -1
  116. package/plugins/beta/use-location/src/UseLocation.jsx +1 -1
  117. package/plugins/beta/use-location/src/defaults.js +1 -1
  118. package/plugins/beta/use-location/src/events.js +3 -3
  119. package/plugins/interact/dist/css/index.css +1 -1
  120. package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
  121. package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
  122. package/plugins/interact/src/InteractInit.jsx +1 -2
  123. package/plugins/interact/src/api/enable.js +8 -5
  124. package/plugins/interact/src/api/enable.test.js +2 -2
  125. package/plugins/interact/src/api/selectFeature.js +4 -4
  126. package/plugins/interact/src/api/unselectFeature.js +5 -5
  127. package/plugins/interact/src/defaults.js +0 -1
  128. package/plugins/interact/src/events.test.js +15 -15
  129. package/plugins/interact/src/hooks/useHighlightSync.js +1 -1
  130. package/plugins/interact/src/hooks/useInteractionHandlers.js +2 -2
  131. package/plugins/interact/src/hooks/useInteractionHandlers.test.js +5 -5
  132. package/plugins/interact/src/interact.scss +0 -7
  133. package/plugins/interact/src/manifest.js +15 -19
  134. package/plugins/interact/src/manifest.test.js +6 -5
  135. package/plugins/interact/src/reducer.js +3 -3
  136. package/plugins/interact/src/reducer.test.js +0 -1
  137. package/plugins/interact/src/utils/spatial.js +10 -10
  138. package/plugins/interact/src/utils/spatial.test.js +14 -14
  139. package/plugins/search/dist/css/index.css +1 -1
  140. package/plugins/search/dist/esm/im-search-plugin.js +1 -1
  141. package/plugins/search/dist/esm/index.js +1 -1
  142. package/plugins/search/dist/umd/im-search-plugin.js +1 -1
  143. package/plugins/search/dist/umd/index.js +1 -1
  144. package/plugins/search/src/Search.jsx +7 -6
  145. package/plugins/search/src/Search.test.jsx +23 -23
  146. package/plugins/search/src/components/CloseButton/CloseButton.jsx +15 -15
  147. package/plugins/search/src/components/CloseButton/CloseButton.test.jsx +2 -2
  148. package/plugins/search/src/components/Form/Form.jsx +14 -14
  149. package/plugins/search/src/components/Form/Form.module.scss +2 -1
  150. package/plugins/search/src/components/Form/Form.test.jsx +11 -11
  151. package/plugins/search/src/components/OpenButton/OpenButton.jsx +16 -15
  152. package/plugins/search/src/components/OpenButton/OpenButton.test.jsx +6 -2
  153. package/plugins/search/src/components/SubmitButton/SubmitButton.jsx +15 -15
  154. package/plugins/search/src/components/Suggestions/Suggestions.jsx +6 -6
  155. package/plugins/search/src/components/Suggestions/Suggestions.test.jsx +4 -4
  156. package/plugins/search/src/datasets.js +12 -13
  157. package/plugins/search/src/datasets.test.js +1 -1
  158. package/plugins/search/src/defaults.js +1 -1
  159. package/plugins/search/src/events/fetchSuggestions.js +3 -3
  160. package/plugins/search/src/events/fetchSuggestions.test.js +1 -1
  161. package/plugins/search/src/events/formHandlers.js +3 -3
  162. package/plugins/search/src/events/formHandlers.test.js +1 -1
  163. package/plugins/search/src/events/index.js +2 -2
  164. package/plugins/search/src/events/index.test.js +2 -2
  165. package/plugins/search/src/events/inputHandlers.js +4 -4
  166. package/plugins/search/src/events/inputHandlers.test.js +1 -1
  167. package/plugins/search/src/events/suggestionHandlers.js +2 -2
  168. package/plugins/search/src/events/suggestionHandlers.test.js +1 -1
  169. package/plugins/search/src/index.js +2 -1
  170. package/plugins/search/src/index.test.js +3 -3
  171. package/plugins/search/src/manifest.js +6 -4
  172. package/plugins/search/src/reducer.js +1 -2
  173. package/plugins/search/src/reducer.test.js +2 -2
  174. package/plugins/search/src/search.scss +10 -3
  175. package/plugins/search/src/utils/parseOsNamesResults.js +1 -2
  176. package/plugins/search/src/utils/parseOsNamesResults.test.js +2 -2
  177. package/plugins/search/src/utils/updateMap.js +1 -1
  178. package/plugins/search/src/utils/updateMap.test.js +5 -5
  179. package/providers/beta/esri/dist/esm/im-esri-provider.js +1 -1
  180. package/providers/beta/esri/src/esriProvider.js +5 -5
  181. package/providers/beta/esri/src/utils/coords.js +1 -1
  182. package/providers/beta/esri/src/utils/esriFixes.js +1 -1
  183. package/providers/beta/esri/src/utils/query.js +4 -4
  184. package/providers/beta/esri/src/utils/spatial.js +1 -2
  185. package/providers/beta/esri/src/utils/spatial.test.js +4 -1
  186. package/providers/beta/open-names/src/utils/mapToLocationModel.test.js +1 -1
  187. package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
  188. package/providers/maplibre/dist/umd/im-maplibre-framework.js +1 -1
  189. package/providers/maplibre/dist/umd/im-maplibre-framework.js.LICENSE.txt +1 -1
  190. package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
  191. package/providers/maplibre/src/appEvents.test.js +1 -1
  192. package/providers/maplibre/src/index.js +1 -1
  193. package/providers/maplibre/src/index.test.js +3 -5
  194. package/providers/maplibre/src/mapEvents.test.js +15 -5
  195. package/providers/maplibre/src/maplibreProvider.test.js +6 -2
  196. package/providers/maplibre/src/utils/calculateLinearTextSize.js +4 -4
  197. package/providers/maplibre/src/utils/calculateLinearTextSize.test.js +3 -3
  198. package/providers/maplibre/src/utils/detectWebgl.test.js +1 -1
  199. package/providers/maplibre/src/utils/highlightFeatures.js +3 -2
  200. package/providers/maplibre/src/utils/highlightFeatures.test.js +13 -6
  201. package/providers/maplibre/src/utils/labels.js +19 -20
  202. package/providers/maplibre/src/utils/labels.test.js +15 -13
  203. package/providers/maplibre/src/utils/maplibreFixes.test.js +1 -1
  204. package/providers/maplibre/src/utils/queryFeatures.js +6 -6
  205. package/providers/maplibre/src/utils/queryFeatures.test.js +13 -13
  206. package/providers/maplibre/src/utils/spatial.js +0 -1
  207. package/providers/maplibre/src/utils/spatial.test.js +26 -27
  208. package/src/App/components/Actions/Actions.jsx +2 -2
  209. package/src/App/components/Actions/Actions.module.scss +0 -7
  210. package/src/App/components/Actions/Actions.test.jsx +1 -1
  211. package/src/App/components/Icon/Icon.jsx +3 -2
  212. package/src/App/components/Icon/Icon.module.scss +4 -0
  213. package/src/App/components/Icon/Icon.test.jsx +43 -4
  214. package/src/App/components/MapButton/MapButton.jsx +42 -17
  215. package/src/App/components/MapButton/MapButton.module.scss +4 -13
  216. package/src/App/components/MapButton/MapButton.test.jsx +27 -3
  217. package/src/App/components/PopupMenu/PopupMenu.jsx +51 -274
  218. package/src/App/components/PopupMenu/PopupMenu.module.scss +14 -7
  219. package/src/App/components/PopupMenu/PopupMenu.test.jsx +70 -1
  220. package/src/App/components/PopupMenu/usePopupMenu.js +258 -0
  221. package/src/App/hooks/useButtonStateEvaluator.js +12 -2
  222. package/src/App/hooks/useButtonStateEvaluator.test.js +38 -4
  223. package/src/App/hooks/useInterfaceAPI.js +6 -0
  224. package/src/App/hooks/useLayoutMeasurements.js +84 -18
  225. package/src/App/hooks/useLayoutMeasurements.test.js +124 -17
  226. package/src/App/layout/Layout.jsx +12 -7
  227. package/src/App/layout/Layout.test.jsx +2 -2
  228. package/src/App/layout/layout.module.scss +67 -29
  229. package/src/App/registry/pluginRegistry.js +17 -0
  230. package/src/App/registry/pluginRegistry.test.js +33 -0
  231. package/src/App/renderer/HtmlElementHost.jsx +2 -1
  232. package/src/App/renderer/HtmlElementHost.test.jsx +7 -7
  233. package/src/App/renderer/mapButtons.js +3 -2
  234. package/src/App/renderer/mapPanels.test.js +2 -2
  235. package/src/App/renderer/slotHelpers.js +2 -2
  236. package/src/App/renderer/slotHelpers.test.js +5 -5
  237. package/src/App/renderer/slots.js +9 -5
  238. package/src/App/store/AppProvider.jsx +3 -1
  239. package/src/App/store/AppProvider.test.jsx +1 -1
  240. package/src/App/store/ServiceProvider.jsx +3 -1
  241. package/src/App/store/appActionsMap.js +16 -0
  242. package/src/App/store/appActionsMap.test.js +27 -0
  243. package/src/App/store/appDispatchMiddleware.js +33 -1
  244. package/src/App/store/appDispatchMiddleware.test.js +250 -222
  245. package/src/App/store/appReducer.js +2 -0
  246. package/src/InteractiveMap/InteractiveMap.js +4 -0
  247. package/src/config/appConfig.js +7 -4
  248. package/src/config/events.js +28 -0
  249. package/src/scss/main.scss +1 -0
  250. package/src/scss/settings/_dimensions.scss +0 -1
  251. package/src/services/logger.js +6 -0
  252. package/src/services/logger.test.js +32 -0
  253. package/src/utils/getSafeZoneInset.js +9 -7
  254. package/src/utils/getSafeZoneInset.test.js +10 -10
  255. package/webpack.dev.mjs +23 -19
  256. package/docs/govuk-prototype.md +0 -23
  257. package/docs/index.md +0 -19
  258. package/plugins/beta/datasets/src/api/hideDataset.js +0 -14
  259. package/plugins/beta/datasets/src/api/hideFeatures.js +0 -41
  260. package/plugins/beta/datasets/src/api/showDataset.js +0 -14
  261. package/plugins/beta/datasets/src/api/showFeatures.js +0 -44
  262. package/plugins/beta/datasets/src/handleSetMapStyle.js +0 -54
  263. package/plugins/beta/datasets/src/mapLayers.js +0 -165
@@ -39,7 +39,7 @@ export const createDrawMode = (ParentMode, config) => {
39
39
  return {
40
40
  ...ParentMode,
41
41
 
42
- onSetup(options) {
42
+ onSetup (options) {
43
43
  const { map } = this
44
44
 
45
45
  // Some parent modes (DrawLineString) interpret featureId as "continue existing"
@@ -97,7 +97,7 @@ export const createDrawMode = (ParentMode, config) => {
97
97
  return state
98
98
  },
99
99
 
100
- onClick(state, e) {
100
+ onClick (state, e) {
101
101
  // Skip non-primary clicks, undo operations, or clicks outside canvas
102
102
  if (e.originalEvent.button > 0 || this.map._undoInProgress || e.originalEvent.target !== this.map.getCanvas()) {
103
103
  return
@@ -119,11 +119,11 @@ export const createDrawMode = (ParentMode, config) => {
119
119
  }
120
120
  },
121
121
 
122
- onTap() {
123
- return
122
+ onTap () {
123
+
124
124
  },
125
125
 
126
- doClick(state) {
126
+ doClick (state) {
127
127
  // Skip during undo operation
128
128
  if (this.map._undoInProgress) {
129
129
  return
@@ -160,7 +160,7 @@ export const createDrawMode = (ParentMode, config) => {
160
160
  }
161
161
  },
162
162
 
163
- dispatchVertexChange(coords) {
163
+ dispatchVertexChange (coords) {
164
164
  this.map.fire('draw.vertexchange', {
165
165
  numVertecies: coords.length
166
166
  })
@@ -169,7 +169,7 @@ export const createDrawMode = (ParentMode, config) => {
169
169
  /**
170
170
  * Push an undo operation for the last added vertex
171
171
  */
172
- pushDrawUndo(state) {
172
+ pushDrawUndo (state) {
173
173
  const undoStack = this.map._undoStack
174
174
  // Don't push during undo operations
175
175
  if (!undoStack || this.map._undoInProgress) {
@@ -185,7 +185,7 @@ export const createDrawMode = (ParentMode, config) => {
185
185
  /**
186
186
  * Undo the last added vertex during drawing
187
187
  */
188
- undoVertex(state) {
188
+ undoVertex (state) {
189
189
  const feature = getFeature(state)
190
190
  const coords = getCoords(feature)
191
191
 
@@ -207,7 +207,7 @@ export const createDrawMode = (ParentMode, config) => {
207
207
  * For Polygon: reinitialize in place
208
208
  * For LineString: restart the draw mode with fresh state
209
209
  */
210
- _reinitializeFeature(state, feature) {
210
+ _reinitializeFeature (state, feature) {
211
211
  const featureId = feature.id
212
212
  this._ctx.store.delete([featureId])
213
213
 
@@ -258,7 +258,7 @@ export const createDrawMode = (ParentMode, config) => {
258
258
  /**
259
259
  * Remove the last committed vertex and update rubber band
260
260
  */
261
- _removeLastVertex(state, feature, coords) {
261
+ _removeLastVertex (state, feature, coords) {
262
262
  // Structure during drawing: [v1, v2, ..., vN, rubber_band]
263
263
  const ring = geometryType === 'Polygon' ? feature.coordinates[0] : coords
264
264
  ring.splice(ring.length - 2, 1)
@@ -279,7 +279,7 @@ export const createDrawMode = (ParentMode, config) => {
279
279
  /**
280
280
  * Update rubber band position based on interface type
281
281
  */
282
- _updateRubberBand(state, coords) {
282
+ _updateRubberBand (state, coords) {
283
283
  if (['touch', 'keyboard'].includes(state.interfaceType)) {
284
284
  // Touch/keyboard: move to map center for add point to work
285
285
  this._simulateMouse('mousemove', ParentMode.onMouseMove, state)
@@ -305,13 +305,13 @@ export const createDrawMode = (ParentMode, config) => {
305
305
  /**
306
306
  * Handle draw.undo event
307
307
  */
308
- onUndo(state, e) {
308
+ onUndo (state, e) {
309
309
  if (e.operation?.type === 'draw_vertex') {
310
310
  this.undoVertex(state)
311
311
  }
312
312
  },
313
313
 
314
- _simulateMouse(type, fn, state) {
314
+ _simulateMouse (type, fn, state) {
315
315
  const { map } = this
316
316
  const center = map.getCenter()
317
317
  const point = map.project(center)
@@ -330,14 +330,14 @@ export const createDrawMode = (ParentMode, config) => {
330
330
  this.map.fire('draw.geometrychange', state.polygon || state.line)
331
331
  },
332
332
 
333
- _setInterface(state, type, show = true) {
333
+ _setInterface (state, type, show = true) {
334
334
  state.interfaceType = type
335
335
  if (show) {
336
336
  state.vertexMarker.style.display = 'block'
337
337
  }
338
338
  },
339
339
 
340
- onCreate(state, e) {
340
+ onCreate (state, e) {
341
341
  const draw = this._ctx.api
342
342
  const feature = e.features[0]
343
343
  draw.delete(feature.id)
@@ -345,24 +345,24 @@ export const createDrawMode = (ParentMode, config) => {
345
345
  draw.add(feature, { userProperties: true })
346
346
  },
347
347
 
348
- onVertexButtonClick(state, e) {
348
+ onVertexButtonClick (state, e) {
349
349
  // Only trigger for the specific add vertex button, and skip during undo
350
350
  if (state.addVertexButtonId && !this.map._undoInProgress && e.target.closest(`#${state.addVertexButtonId}`)) {
351
351
  this.doClick(state)
352
352
  }
353
353
  },
354
354
 
355
- onTouchStart(state, e) {
355
+ onTouchStart (state, e) {
356
356
  this._setInterface(state, 'touch')
357
357
  this.onMove(state, e)
358
358
  },
359
359
 
360
- onTouchEnd(state, e) {
360
+ onTouchEnd (state, e) {
361
361
  this._setInterface(state, 'touch')
362
362
  this.onMove(state, e)
363
363
  },
364
364
 
365
- onKeydown(state, e) {
365
+ onKeydown (state, e) {
366
366
  // Undo with Cmd/Ctrl+Z (works without viewport focus, but not in input fields)
367
367
  if (e.key === 'z' && (e.metaKey || e.ctrlKey) && !e.shiftKey) {
368
368
  const tag = document.activeElement?.tagName
@@ -396,7 +396,7 @@ export const createDrawMode = (ParentMode, config) => {
396
396
  this.onMove(state, e)
397
397
  },
398
398
 
399
- onKeyup(state, e) {
399
+ onKeyup (state, e) {
400
400
  if (e.key === 'Escape') {
401
401
  if (state.interfaceType !== 'keyboard') {
402
402
  // Mouse/touch: cancel drawing — onKeyUp (capital U) won't fire since container isn't focused
@@ -420,7 +420,7 @@ export const createDrawMode = (ParentMode, config) => {
420
420
  // 1. A UI element inside the viewport has focus (e.g. popup menu) → ignore, let React handle
421
421
  // 2. Keyboard drawing (container focused, interfaceType === 'keyboard') → Escape restarts
422
422
  // 3. Non-keyboard with container focused → skip (already handled by window onKeyup via draw.cancel)
423
- onKeyUp(state, e) {
423
+ onKeyUp (state, e) {
424
424
  const activeEl = document.activeElement
425
425
  if (activeEl && activeEl !== state.container && state.container.contains(activeEl)) {
426
426
  return
@@ -441,17 +441,17 @@ export const createDrawMode = (ParentMode, config) => {
441
441
  }
442
442
  },
443
443
 
444
- onFocus(state) {
444
+ onFocus (state) {
445
445
  state.vertexMarker.style.display = ['touch', 'keyboard'].includes(state.interfaceType) ? 'block' : 'none'
446
446
  },
447
447
 
448
- onBlur(state, e) {
448
+ onBlur (state, e) {
449
449
  if (e.target !== state.container) {
450
450
  state.vertexMarker.style.display = 'none'
451
451
  }
452
452
  },
453
453
 
454
- onMouseMove(state, e) {
454
+ onMouseMove (state, e) {
455
455
  if (isSnapEnabled(state)) {
456
456
  const snap = getSnapInstance(this.map)
457
457
  triggerSnapAtPoint(snap, this.map, e.point)
@@ -463,11 +463,11 @@ export const createDrawMode = (ParentMode, config) => {
463
463
  }
464
464
 
465
465
  this.map.fire('draw.geometrychange', state.polygon || state.line)
466
-
466
+
467
467
  ParentMode.onMouseMove.call(this, state, e)
468
468
  },
469
469
 
470
- onMove(state) {
470
+ onMove (state) {
471
471
  if (['touch', 'keyboard'].includes(state.interfaceType)) {
472
472
  if (isSnapEnabled(state)) {
473
473
  triggerSnapAtCenter(getSnapInstance(this.map), this.map)
@@ -495,23 +495,23 @@ export const createDrawMode = (ParentMode, config) => {
495
495
  }
496
496
  },
497
497
 
498
- onPointerdown(state, e) {
498
+ onPointerdown (state, e) {
499
499
  if (e.pointerType !== 'touch') {
500
500
  this._setInterface(state, 'pointer', false)
501
501
  }
502
502
  },
503
503
 
504
- onPointermove(state, e) {
504
+ onPointermove (state, e) {
505
505
  if (e.pointerType !== 'touch') {
506
506
  state.vertexMarker.style.display = 'none'
507
507
  }
508
508
  },
509
509
 
510
- onPointerup(state) {
510
+ onPointerup (state) {
511
511
  this.dispatchVertexChange(getCoords(getFeature(state)))
512
512
  },
513
513
 
514
- toDisplayFeatures(state, geojson, display) {
514
+ toDisplayFeatures (state, geojson, display) {
515
515
  ParentMode.toDisplayFeatures.call(this, state, geojson, display)
516
516
 
517
517
  const feature = getFeature(state)
@@ -520,7 +520,7 @@ export const createDrawMode = (ParentMode, config) => {
520
520
  }
521
521
  },
522
522
 
523
- onStop(state) {
523
+ onStop (state) {
524
524
  ParentMode.onStop.call(this, state)
525
525
  this._listeners.forEach(([t, e, h]) => t.removeEventListener ? t.removeEventListener(e, h) : t.off(e, h))
526
526
  state.vertexMarker.style.display = 'none'
@@ -20,4 +20,4 @@ export const DisabledMode = {
20
20
  geojson.properties.active = 'false'
21
21
  display(geojson)
22
22
  }
23
- }
23
+ }
@@ -13,7 +13,7 @@ const touchVertexTarget = `
13
13
  `
14
14
 
15
15
  export const touchHandlers = {
16
- addTouchVertexTarget(state) {
16
+ addTouchVertexTarget (state) {
17
17
  let el = state.container.querySelector('[data-touch-vertex-target]')
18
18
  if (!el) {
19
19
  state.container.insertAdjacentHTML('beforeend', touchVertexTarget)
@@ -22,7 +22,7 @@ export const touchHandlers = {
22
22
  state.touchVertexTarget = el
23
23
  },
24
24
 
25
- updateTouchVertexTarget(state, point) {
25
+ updateTouchVertexTarget (state, point) {
26
26
  if (point && state.interfaceType === 'touch' && state.selectedVertexIndex >= 0) {
27
27
  Object.assign(state.touchVertexTarget.style, { display: 'block', top: `${point.y}px`, left: `${point.x}px` })
28
28
  } else {
@@ -30,11 +30,11 @@ export const touchHandlers = {
30
30
  }
31
31
  },
32
32
 
33
- hideTouchVertexIndicator(state) {
33
+ hideTouchVertexIndicator (state) {
34
34
  state.touchVertexTarget.style.display = 'none'
35
35
  },
36
36
 
37
- onPointerevent(state, e) {
37
+ onPointerevent (state, e) {
38
38
  state.interfaceType = e.pointerType === 'touch' ? 'touch' : 'pointer'
39
39
  state.isPanEnabled = true
40
40
  if (e.pointerType === 'touch' && e.type === 'pointermove' && !isOnSVG(e.target.parentNode) && !state._ignorePointermoveDeselect) {
@@ -43,11 +43,11 @@ export const touchHandlers = {
43
43
  },
44
44
 
45
45
  // Empty stubs required by DirectSelect
46
- onTouchStart() {},
47
- onTouchMove() {},
48
- onTouchEnd() {},
46
+ onTouchStart () {},
47
+ onTouchMove () {},
48
+ onTouchEnd () {},
49
49
 
50
- onTouchend(state) {
50
+ onTouchend (state) {
51
51
  clearSnapState(getSnapInstance(this.map))
52
52
  if (state?.featureId) {
53
53
  this.syncVertices(state)
@@ -67,7 +67,7 @@ export const touchHandlers = {
67
67
  }
68
68
  },
69
69
 
70
- onTap(state, e) {
70
+ onTap (state, e) {
71
71
  // Hide snap indicator on any tap
72
72
  const snap = getSnapInstance(this.map)
73
73
  if (snap) {
@@ -92,7 +92,7 @@ export const touchHandlers = {
92
92
  }
93
93
  },
94
94
 
95
- onTouchstart(state, e) {
95
+ onTouchstart (state, e) {
96
96
  clearSnapState(getSnapInstance(this.map))
97
97
  const vertex = state.vertecies?.[state.selectedVertexIndex]
98
98
  if (!vertex || !isOnSVG(e.target.parentNode)) {
@@ -111,7 +111,7 @@ export const touchHandlers = {
111
111
  state.deltaVertex = { x: (touch.x / state.scale) - vertexPt.x, y: (touch.y / state.scale) - vertexPt.y }
112
112
  },
113
113
 
114
- onTouchmove(state, e) {
114
+ onTouchmove (state, e) {
115
115
  if (state.selectedVertexIndex < 0 || !isOnSVG(e.target.parentNode)) {
116
116
  return
117
117
  }
@@ -7,7 +7,7 @@ import { scalePoint } from './helpers.js'
7
7
 
8
8
  export const undoHandlers = {
9
9
  // Fire geometry change event (for external listeners)
10
- fireGeometryChange(state) {
10
+ fireGeometryChange (state) {
11
11
  const feature = this.getFeature(state.featureId)
12
12
  if (feature) {
13
13
  this.map.fire('draw.update', {
@@ -18,7 +18,7 @@ export const undoHandlers = {
18
18
  },
19
19
 
20
20
  // Undo support
21
- pushUndo(operation) {
21
+ pushUndo (operation) {
22
22
  const undoStack = this.map._undoStack
23
23
  if (!undoStack) {
24
24
  return
@@ -26,7 +26,7 @@ export const undoHandlers = {
26
26
  undoStack.push(operation)
27
27
  },
28
28
 
29
- handleUndo(state) {
29
+ handleUndo (state) {
30
30
  const undoStack = this.map._undoStack
31
31
  if (!undoStack || undoStack.length === 0) {
32
32
  return
@@ -43,7 +43,7 @@ export const undoHandlers = {
43
43
  }
44
44
  },
45
45
 
46
- undoMoveVertex(state, op) {
46
+ undoMoveVertex (state, op) {
47
47
  const { vertexIndex, previousPosition, featureId } = op
48
48
  const feature = this.getFeature(featureId)
49
49
  if (!feature) return
@@ -64,7 +64,7 @@ export const undoHandlers = {
64
64
  }
65
65
  },
66
66
 
67
- undoInsertVertex(state, op) {
67
+ undoInsertVertex (state, op) {
68
68
  const { vertexIndex, featureId } = op
69
69
  const feature = this.getFeature(featureId)
70
70
  if (!feature) return
@@ -84,7 +84,7 @@ export const undoHandlers = {
84
84
  this.changeMode(state, { selectedVertexIndex: -1, selectedVertexType: null })
85
85
  },
86
86
 
87
- undoDeleteVertex(state, op) {
87
+ undoDeleteVertex (state, op) {
88
88
  const { vertexIndex, position, featureId } = op
89
89
  const feature = this.getFeature(featureId)
90
90
  if (!feature) {
@@ -123,7 +123,7 @@ export const undoHandlers = {
123
123
  this.changeMode(state, { selectedVertexIndex: vertexIndex, selectedVertexType: 'vertex', coordPath: this.getCoordPath(state, vertexIndex) })
124
124
  },
125
125
 
126
- _applyUndoAndSync(state, geojson, featureId) {
126
+ _applyUndoAndSync (state, geojson, featureId) {
127
127
  this._ctx.api.add(geojson)
128
128
  state.vertecies = this.getVerticies(featureId)
129
129
  state.midpoints = this.getMidpoints(featureId)
@@ -6,10 +6,10 @@ import {
6
6
  } from './geometryHelpers.js'
7
7
 
8
8
  const ARROW_OFFSETS = { ArrowUp: [0, -1], ArrowDown: [0, 1], ArrowLeft: [-1, 0], ArrowRight: [1, 0] }
9
- const NUDGE = 1, STEP = 5
9
+ const NUDGE = 1; const STEP = 5
10
10
 
11
11
  export const vertexOperations = {
12
- updateMidpoint(coordinates) {
12
+ updateMidpoint (coordinates) {
13
13
  setTimeout(() => {
14
14
  this.map.getSource('mapbox-gl-draw-hot').setData({
15
15
  type: 'Feature',
@@ -19,7 +19,7 @@ export const vertexOperations = {
19
19
  }, 0)
20
20
  },
21
21
 
22
- updateVertex(state, direction) {
22
+ updateVertex (state, direction) {
23
23
  const [idx, type] = this.getVertexOrMidpoint(state, direction)
24
24
  if (idx < 0 || !type) {
25
25
  return
@@ -27,18 +27,18 @@ export const vertexOperations = {
27
27
  this.changeMode(state, { selectedVertexIndex: idx, selectedVertexType: type, ...(type === 'vertex' && { coordPath: this.getCoordPath(state, idx) }) })
28
28
  },
29
29
 
30
- getOffset(coord, e) {
30
+ getOffset (coord, e) {
31
31
  const pt = this.map.project(coord)
32
32
  const offset = e?.shiftKey ? NUDGE : STEP
33
33
  const [dx, dy] = e ? ARROW_OFFSETS[e.key].map(v => v * offset) : [0, 0]
34
34
  return this.map.unproject({ x: pt.x + dx, y: pt.y + dy })
35
35
  },
36
36
 
37
- getNewCoord(state, e) {
37
+ getNewCoord (state, e) {
38
38
  return this.getOffset(getCoords(this.getFeature(state.featureId))[state.selectedVertexIndex], e)
39
39
  },
40
40
 
41
- insertVertex(state, e) {
41
+ insertVertex (state, e) {
42
42
  const midIdx = state.selectedVertexIndex - state.vertecies.length
43
43
  const newCoord = this.getOffset(state.midpoints[midIdx], e)
44
44
  const feature = this.getFeature(state.featureId)
@@ -74,7 +74,7 @@ export const vertexOperations = {
74
74
  this.changeMode(state, { selectedVertexIndex: globalInsertIdx, selectedVertexType: 'vertex', coordPath: this.getCoordPath(state, globalInsertIdx) })
75
75
  },
76
76
 
77
- moveVertex(state, coord, options = {}) {
77
+ moveVertex (state, coord, options = {}) {
78
78
  if (options.checkSnap && state.enableSnap !== false) {
79
79
  const snap = this.map._snapInstance
80
80
  if (snap?.snapStatus && snap.snapCoords?.length >= 2) {
@@ -96,7 +96,7 @@ export const vertexOperations = {
96
96
  this.map.fire('draw.geometrychange', state.feature)
97
97
  },
98
98
 
99
- deleteVertex(state) {
99
+ deleteVertex (state) {
100
100
  const feature = this.getFeature(state.featureId)
101
101
  if (!feature) {
102
102
  return
@@ -6,7 +6,7 @@ import {
6
6
  import { spatialNavigate } from '../../utils/spatial.js'
7
7
 
8
8
  export const vertexQueries = {
9
- findVertexIndex(coords, targetCoord, currentIdx) {
9
+ findVertexIndex (coords, targetCoord, currentIdx) {
10
10
  // Search for vertex, preferring matches near currentIdx to handle duplicate coords (e.g., closing vertices)
11
11
  const matches = []
12
12
  coords.forEach((c, i) => {
@@ -27,7 +27,7 @@ export const vertexQueries = {
27
27
  return matches[0]
28
28
  },
29
29
 
30
- getCoordPath(state, idx) {
30
+ getCoordPath (state, idx) {
31
31
  const feature = this.getFeature(state.featureId)
32
32
  if (!feature) return '0'
33
33
 
@@ -39,16 +39,16 @@ export const vertexQueries = {
39
39
  return [...segment.path, localIdx].join('.')
40
40
  },
41
41
 
42
- syncVertices(state) {
42
+ syncVertices (state) {
43
43
  state.vertecies = this.getVerticies(state.featureId)
44
44
  state.midpoints = this.getMidpoints(state.featureId)
45
45
  },
46
46
 
47
- getVerticies(featureId) {
47
+ getVerticies (featureId) {
48
48
  return getCoords(this.getFeature(featureId)) || []
49
49
  },
50
50
 
51
- getMidpoints(featureId) {
51
+ getMidpoints (featureId) {
52
52
  const feature = this.getFeature(featureId)
53
53
  const coords = getCoords(feature)
54
54
  const segments = getRingSegments(feature)
@@ -73,7 +73,7 @@ export const vertexQueries = {
73
73
  return midpoints
74
74
  },
75
75
 
76
- getVertexOrMidpoint(state, direction) {
76
+ getVertexOrMidpoint (state, direction) {
77
77
  // Ensure vertices and midpoints are populated
78
78
  if (!state.vertecies?.length) {
79
79
  state.vertecies = this.getVerticies(state.featureId)
@@ -92,7 +92,7 @@ export const vertexQueries = {
92
92
  return [idx, idx < state.vertecies.length ? 'vertex' : 'midpoint']
93
93
  },
94
94
 
95
- getVertexIndexFromMidpoint(state, coordPath) {
95
+ getVertexIndexFromMidpoint (state, coordPath) {
96
96
  const feature = this.getFeature(state.featureId)
97
97
  const segments = getRingSegments(feature)
98
98
  const parts = coordPath.split('.').map(Number)
@@ -20,7 +20,7 @@ export const EditVertexMode = {
20
20
  ...vertexOperations,
21
21
  ...vertexQueries,
22
22
 
23
- onSetup(options) {
23
+ onSetup (options) {
24
24
  const state = DirectSelect.onSetup.call(this, options)
25
25
  Object.assign(state, {
26
26
  container: options.container,
@@ -88,15 +88,22 @@ export const EditVertexMode = {
88
88
  return state
89
89
  },
90
90
 
91
- setupEventListeners(state) {
91
+ setupEventListeners (state) {
92
92
  const bind = (fn) => (e) => fn.call(this, state, e)
93
93
  const h = this.handlers = {
94
- keydown: bind(this.onKeydown), keyup: bind(this.onKeyup),
95
- pointerdown: bind(this.onPointerevent), pointermove: bind(this.onPointerevent), pointerup: bind(this.onPointerevent),
94
+ keydown: bind(this.onKeydown),
95
+ keyup: bind(this.onKeyup),
96
+ pointerdown: bind(this.onPointerevent),
97
+ pointermove: bind(this.onPointerevent),
98
+ pointerup: bind(this.onPointerevent),
96
99
  click: bind(this.onButtonClick),
97
- touchstart: bind(this.onTouchstart), touchmove: bind(this.onTouchmove), touchend: bind(this.onTouchend),
98
- selectionchange: bind(this.onSelectionChange), scalechange: bind(this.onScaleChange),
99
- update: bind(this.onUpdate), move: bind(this.onMove)
100
+ touchstart: bind(this.onTouchstart),
101
+ touchmove: bind(this.onTouchmove),
102
+ touchend: bind(this.onTouchend),
103
+ selectionchange: bind(this.onSelectionChange),
104
+ scalechange: bind(this.onScaleChange),
105
+ update: bind(this.onUpdate),
106
+ move: bind(this.onMove)
100
107
  }
101
108
 
102
109
  window.addEventListener('keydown', h.keydown, { capture: true })
@@ -114,7 +121,7 @@ export const EditVertexMode = {
114
121
  this.map.on('move', h.move)
115
122
  },
116
123
 
117
- onSelectionChange(state, e) {
124
+ onSelectionChange (state, e) {
118
125
  const vertexCoord = e.points[e.points.length - 1]?.geometry.coordinates
119
126
 
120
127
  // Only update selectedVertexIndex from event if not keyboard mode AND event has valid vertex
@@ -139,11 +146,11 @@ export const EditVertexMode = {
139
146
  this.updateTouchVertexTarget(state, vertex ? scalePoint(this.map.project(vertex), state.scale) : null)
140
147
  },
141
148
 
142
- onScaleChange(state, e) {
149
+ onScaleChange (state, e) {
143
150
  state.scale = e.scale
144
151
  },
145
152
 
146
- onUpdate(state) {
153
+ onUpdate (state) {
147
154
  const prev = new Set(state.vertecies.map(c => JSON.stringify(c)))
148
155
  if (prev.size === state.vertecies.length) {
149
156
  return
@@ -152,7 +159,7 @@ export const EditVertexMode = {
152
159
  state.selectedVertexType ??= state.selectedVertexIndex >= 0 ? 'vertex' : null
153
160
  },
154
161
 
155
- onKeydown(state, e) {
162
+ onKeydown (state, e) {
156
163
  if (!state.container.contains(document.activeElement)) {
157
164
  return
158
165
  }
@@ -247,7 +254,7 @@ export const EditVertexMode = {
247
254
  }
248
255
  },
249
256
 
250
- onKeyup(state, e) {
257
+ onKeyup (state, e) {
251
258
  if (!state.container.contains(document.activeElement)) {
252
259
  return
253
260
  }
@@ -273,7 +280,7 @@ export const EditVertexMode = {
273
280
  }
274
281
  },
275
282
 
276
- onMouseDown(state, e) {
283
+ onMouseDown (state, e) {
277
284
  clearSnapState(getSnapInstance(this.map))
278
285
  const meta = e.featureTarget?.properties.meta
279
286
  const coordPath = e.featureTarget?.properties.coord_path
@@ -313,7 +320,7 @@ export const EditVertexMode = {
313
320
  }
314
321
  },
315
322
 
316
- onMouseUp(state, e) {
323
+ onMouseUp (state, e) {
317
324
  clearSnapState(getSnapInstance(this.map))
318
325
 
319
326
  // Check if vertex actually moved by comparing current position to start position
@@ -353,10 +360,11 @@ export const EditVertexMode = {
353
360
  state._insertedVertexIndex = undefined
354
361
  // Broadcast the updated vertex count — DirectSelect.onMouseUp only fires
355
362
  // draw.update (not draw.selectionchange), so onSelectionChange never runs
356
- this.map.fire('draw.vertexselection', { index: insertedIndex, numVertecies: state.vertecies.length })
357
- }
358
- // Push undo for the move if vertex actually moved
359
- else if (vertexMoved && state._moveStartPosition && state._moveStartIndex !== undefined) {
363
+ this.map.fire('draw.vertexselection', {
364
+ index: insertedIndex, numVertecies: state.vertecies.length
365
+ })
366
+ } else if (vertexMoved && state._moveStartPosition && state._moveStartIndex !== undefined) {
367
+ // Push undo for the move if vertex actually moved
360
368
  this.pushUndo({
361
369
  type: 'move_vertex',
362
370
  featureId: state.featureId,
@@ -373,7 +381,7 @@ export const EditVertexMode = {
373
381
  DirectSelect.onMouseUp.call(this, state, e)
374
382
  },
375
383
 
376
- onDrag(state, e) {
384
+ onDrag (state, e) {
377
385
  if (state.interfaceType === 'touch') {
378
386
  return
379
387
  }
@@ -404,14 +412,14 @@ export const EditVertexMode = {
404
412
  state.dragMoveLocation = e.lngLat
405
413
  },
406
414
 
407
- onMove(state) {
415
+ onMove (state) {
408
416
  const vertex = state.vertecies[state.selectedVertexIndex]
409
417
  if (vertex) {
410
418
  this.updateTouchVertexTarget(state, scalePoint(this.map.project(vertex), state.scale))
411
419
  }
412
420
  },
413
421
 
414
- onButtonClick(state, e) {
422
+ onButtonClick (state, e) {
415
423
  if (e.target.closest(`#${state.deleteVertexButtonId}`) && state.selectedVertexType === 'vertex') {
416
424
  this.deleteVertex(state)
417
425
  }
@@ -420,19 +428,19 @@ export const EditVertexMode = {
420
428
  }
421
429
  },
422
430
 
423
- clickNoTarget(state) {
431
+ clickNoTarget (state) {
424
432
  this.changeMode(state, { selectedVertexIndex: -1, selectedVertexType: null, isPanEnabled: true })
425
433
  },
426
434
 
427
435
  // Prevent selecting other features
428
- changeMode(state, updates) {
436
+ changeMode (state, updates) {
429
437
  if (!state.featureId) {
430
438
  return
431
439
  }
432
440
  this._ctx.api.changeMode('edit_vertex', { ...state, ...updates })
433
441
  },
434
442
 
435
- onStop(state) {
443
+ onStop (state) {
436
444
  const h = this.handlers
437
445
  state.container.removeEventListener('pointerdown', h.pointerdown)
438
446
  state.container.removeEventListener('pointermove', h.pointermove)
@@ -84,4 +84,4 @@ const actions = {
84
84
  export {
85
85
  initialState,
86
86
  actions
87
- }
87
+ }