@defra/interactive-map 0.0.15-alpha → 0.0.16-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 (176) 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/dist/esm/im-core.js +1 -1
  5. package/dist/umd/im-core.js +1 -1
  6. package/dist/umd/index.js +1 -1
  7. package/docs/api/slot-map.svg +1 -0
  8. package/docs/api/slots.md +89 -6
  9. package/docs/api.md +1 -1
  10. package/docs/architecture.md +3 -1
  11. package/docs/{demo.mdx → examples.mdx} +1 -1
  12. package/docs/getting-started.md +1 -3
  13. package/docs/index.mdx +42 -0
  14. package/docs/plugins/interact.md +176 -55
  15. package/docs/plugins/map-styles.md +64 -7
  16. package/docs/plugins/search.md +207 -63
  17. package/docs/plugins.md +7 -15
  18. package/docusaurus.config.cjs +34 -34
  19. package/jest.setup.js +1 -1
  20. package/package.json +5 -4
  21. package/plugins/beta/datasets/src/DatasetsInit.jsx +1 -1
  22. package/plugins/beta/datasets/src/api/addDataset.js +1 -1
  23. package/plugins/beta/datasets/src/api/hideDataset.js +1 -1
  24. package/plugins/beta/datasets/src/api/hideFeatures.js +1 -1
  25. package/plugins/beta/datasets/src/api/removeDataset.js +1 -1
  26. package/plugins/beta/datasets/src/api/showDataset.js +1 -1
  27. package/plugins/beta/datasets/src/api/showFeatures.js +1 -1
  28. package/plugins/beta/datasets/src/datasets.js +4 -4
  29. package/plugins/beta/datasets/src/defaults.js +1 -1
  30. package/plugins/beta/datasets/src/fetch/createDynamicSource.js +5 -5
  31. package/plugins/beta/datasets/src/handleSetMapStyle.js +1 -1
  32. package/plugins/beta/datasets/src/manifest.js +3 -3
  33. package/plugins/beta/datasets/src/mapLayers.js +2 -3
  34. package/plugins/beta/datasets/src/panels/Key.jsx +31 -29
  35. package/plugins/beta/datasets/src/panels/Layers.jsx +8 -9
  36. package/plugins/beta/datasets/src/utils/bbox.js +4 -4
  37. package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
  38. package/plugins/beta/draw-es/src/DrawInit.jsx +16 -16
  39. package/plugins/beta/draw-es/src/api/addFeature.js +3 -3
  40. package/plugins/beta/draw-es/src/api/deleteFeature.js +3 -3
  41. package/plugins/beta/draw-es/src/api/editFeature.js +3 -3
  42. package/plugins/beta/draw-es/src/api/newPolygon.js +3 -3
  43. package/plugins/beta/draw-es/src/events.js +52 -20
  44. package/plugins/beta/draw-es/src/events.test.js +301 -0
  45. package/plugins/beta/draw-es/src/graphic.js +1 -1
  46. package/plugins/beta/draw-es/src/manifest.js +4 -4
  47. package/plugins/beta/draw-es/src/reducer.js +1 -1
  48. package/plugins/beta/draw-es/src/sketchViewModel.js +1 -1
  49. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
  50. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
  51. package/plugins/beta/draw-ml/src/DrawInit.jsx +49 -52
  52. package/plugins/beta/draw-ml/src/api/deleteFeature.js +1 -1
  53. package/plugins/beta/draw-ml/src/api/editFeature.js +8 -5
  54. package/plugins/beta/draw-ml/src/api/newLine.js +0 -1
  55. package/plugins/beta/draw-ml/src/api/newPolygon.js +0 -1
  56. package/plugins/beta/draw-ml/src/api/split.js +4 -4
  57. package/plugins/beta/draw-ml/src/defaults.js +1 -1
  58. package/plugins/beta/draw-ml/src/events.js +8 -6
  59. package/plugins/beta/draw-ml/src/manifest.js +15 -15
  60. package/plugins/beta/draw-ml/src/mapboxDraw.js +1 -1
  61. package/plugins/beta/draw-ml/src/mapboxSnap.js +17 -18
  62. package/plugins/beta/draw-ml/src/modes/createDrawMode.js +31 -31
  63. package/plugins/beta/draw-ml/src/modes/disabledMode.js +1 -1
  64. package/plugins/beta/draw-ml/src/modes/editVertex/touchHandlers.js +11 -11
  65. package/plugins/beta/draw-ml/src/modes/editVertex/undoHandlers.js +7 -7
  66. package/plugins/beta/draw-ml/src/modes/editVertex/vertexOperations.js +8 -8
  67. package/plugins/beta/draw-ml/src/modes/editVertex/vertexQueries.js +7 -7
  68. package/plugins/beta/draw-ml/src/modes/editVertexMode.js +32 -24
  69. package/plugins/beta/draw-ml/src/reducer.js +1 -1
  70. package/plugins/beta/draw-ml/src/undoStack.js +4 -4
  71. package/plugins/beta/draw-ml/src/utils/snapHelpers.js +12 -12
  72. package/plugins/beta/draw-ml/src/utils/spatial.js +11 -11
  73. package/plugins/beta/frame/src/Frame.jsx +4 -4
  74. package/plugins/beta/frame/src/FrameInit.jsx +4 -4
  75. package/plugins/beta/frame/src/api/addFrame.js +1 -1
  76. package/plugins/beta/frame/src/api/editFeature.js +1 -1
  77. package/plugins/beta/frame/src/config.js +1 -1
  78. package/plugins/beta/frame/src/manifest.js +3 -3
  79. package/plugins/beta/frame/src/reducer.js +1 -1
  80. package/plugins/beta/frame/src/utils.js +1 -1
  81. package/plugins/beta/map-styles/src/MapStyles.jsx +18 -18
  82. package/plugins/beta/scale-bar/src/ScaleBar.jsx +5 -5
  83. package/plugins/beta/use-location/src/UseLocation.jsx +1 -1
  84. package/plugins/beta/use-location/src/defaults.js +1 -1
  85. package/plugins/beta/use-location/src/events.js +3 -3
  86. package/plugins/interact/src/InteractInit.jsx +1 -2
  87. package/plugins/interact/src/api/enable.js +8 -5
  88. package/plugins/interact/src/api/enable.test.js +2 -2
  89. package/plugins/interact/src/api/selectFeature.js +4 -4
  90. package/plugins/interact/src/api/unselectFeature.js +5 -5
  91. package/plugins/interact/src/defaults.js +0 -1
  92. package/plugins/interact/src/events.test.js +15 -15
  93. package/plugins/interact/src/hooks/useHighlightSync.js +1 -1
  94. package/plugins/interact/src/hooks/useInteractionHandlers.js +2 -2
  95. package/plugins/interact/src/hooks/useInteractionHandlers.test.js +5 -5
  96. package/plugins/interact/src/manifest.js +2 -2
  97. package/plugins/interact/src/manifest.test.js +3 -4
  98. package/plugins/interact/src/reducer.js +3 -3
  99. package/plugins/interact/src/reducer.test.js +0 -1
  100. package/plugins/interact/src/utils/spatial.js +10 -10
  101. package/plugins/interact/src/utils/spatial.test.js +14 -14
  102. package/plugins/search/dist/css/index.css +1 -1
  103. package/plugins/search/dist/esm/im-search-plugin.js +1 -1
  104. package/plugins/search/dist/esm/index.js +1 -1
  105. package/plugins/search/dist/umd/im-search-plugin.js +1 -1
  106. package/plugins/search/dist/umd/index.js +1 -1
  107. package/plugins/search/src/Search.jsx +7 -6
  108. package/plugins/search/src/Search.test.jsx +23 -23
  109. package/plugins/search/src/components/CloseButton/CloseButton.jsx +15 -15
  110. package/plugins/search/src/components/CloseButton/CloseButton.test.jsx +2 -2
  111. package/plugins/search/src/components/Form/Form.jsx +14 -14
  112. package/plugins/search/src/components/Form/Form.test.jsx +11 -11
  113. package/plugins/search/src/components/OpenButton/OpenButton.jsx +16 -15
  114. package/plugins/search/src/components/OpenButton/OpenButton.test.jsx +6 -2
  115. package/plugins/search/src/components/SubmitButton/SubmitButton.jsx +15 -15
  116. package/plugins/search/src/components/Suggestions/Suggestions.jsx +6 -6
  117. package/plugins/search/src/components/Suggestions/Suggestions.test.jsx +4 -4
  118. package/plugins/search/src/datasets.js +12 -13
  119. package/plugins/search/src/datasets.test.js +1 -1
  120. package/plugins/search/src/defaults.js +1 -1
  121. package/plugins/search/src/events/fetchSuggestions.js +3 -3
  122. package/plugins/search/src/events/fetchSuggestions.test.js +1 -1
  123. package/plugins/search/src/events/formHandlers.js +3 -3
  124. package/plugins/search/src/events/formHandlers.test.js +1 -1
  125. package/plugins/search/src/events/index.js +2 -2
  126. package/plugins/search/src/events/index.test.js +2 -2
  127. package/plugins/search/src/events/inputHandlers.js +4 -4
  128. package/plugins/search/src/events/inputHandlers.test.js +1 -1
  129. package/plugins/search/src/events/suggestionHandlers.js +2 -2
  130. package/plugins/search/src/events/suggestionHandlers.test.js +1 -1
  131. package/plugins/search/src/index.js +2 -1
  132. package/plugins/search/src/index.test.js +3 -3
  133. package/plugins/search/src/manifest.js +6 -4
  134. package/plugins/search/src/reducer.js +1 -2
  135. package/plugins/search/src/reducer.test.js +2 -2
  136. package/plugins/search/src/search.scss +10 -3
  137. package/plugins/search/src/utils/parseOsNamesResults.js +1 -2
  138. package/plugins/search/src/utils/parseOsNamesResults.test.js +2 -2
  139. package/plugins/search/src/utils/updateMap.js +1 -1
  140. package/plugins/search/src/utils/updateMap.test.js +5 -5
  141. package/providers/beta/esri/dist/esm/im-esri-provider.js +1 -1
  142. package/providers/beta/esri/src/esriProvider.js +5 -5
  143. package/providers/beta/esri/src/utils/coords.js +1 -1
  144. package/providers/beta/esri/src/utils/esriFixes.js +1 -1
  145. package/providers/beta/esri/src/utils/query.js +4 -4
  146. package/providers/beta/esri/src/utils/spatial.js +1 -2
  147. package/providers/beta/esri/src/utils/spatial.test.js +4 -1
  148. package/providers/beta/open-names/src/utils/mapToLocationModel.test.js +1 -1
  149. package/providers/maplibre/src/appEvents.test.js +1 -1
  150. package/providers/maplibre/src/index.js +1 -1
  151. package/providers/maplibre/src/index.test.js +3 -5
  152. package/providers/maplibre/src/mapEvents.test.js +15 -5
  153. package/providers/maplibre/src/maplibreProvider.test.js +6 -2
  154. package/providers/maplibre/src/utils/calculateLinearTextSize.js +4 -4
  155. package/providers/maplibre/src/utils/calculateLinearTextSize.test.js +3 -3
  156. package/providers/maplibre/src/utils/detectWebgl.test.js +1 -1
  157. package/providers/maplibre/src/utils/highlightFeatures.js +2 -2
  158. package/providers/maplibre/src/utils/highlightFeatures.test.js +12 -6
  159. package/providers/maplibre/src/utils/labels.js +19 -20
  160. package/providers/maplibre/src/utils/labels.test.js +15 -13
  161. package/providers/maplibre/src/utils/maplibreFixes.test.js +1 -1
  162. package/providers/maplibre/src/utils/queryFeatures.js +6 -6
  163. package/providers/maplibre/src/utils/queryFeatures.test.js +13 -13
  164. package/providers/maplibre/src/utils/spatial.js +0 -1
  165. package/providers/maplibre/src/utils/spatial.test.js +26 -27
  166. package/src/App/registry/pluginRegistry.js +17 -0
  167. package/src/App/registry/pluginRegistry.test.js +33 -0
  168. package/src/App/renderer/mapButtons.js +3 -2
  169. package/src/App/store/appDispatchMiddleware.js +33 -1
  170. package/src/App/store/appDispatchMiddleware.test.js +250 -222
  171. package/src/config/appConfig.js +2 -2
  172. package/src/utils/logger.js +6 -0
  173. package/src/utils/logger.test.js +32 -0
  174. package/webpack.dev.mjs +22 -18
  175. package/docs/govuk-prototype.md +0 -23
  176. package/docs/index.md +0 -19
@@ -17,7 +17,7 @@ export const createUndoStack = (map) => {
17
17
  * Push an undo operation onto the stack
18
18
  * @param {Object} operation - { type, undo: Function, ...data }
19
19
  */
20
- push(operation) {
20
+ push (operation) {
21
21
  stack.push(operation)
22
22
  fireChange()
23
23
  },
@@ -26,7 +26,7 @@ export const createUndoStack = (map) => {
26
26
  * Pop and return the last operation (does not execute it)
27
27
  * @returns {Object|undefined} The operation or undefined if empty
28
28
  */
29
- pop() {
29
+ pop () {
30
30
  const op = stack.pop()
31
31
  fireChange()
32
32
  return op
@@ -35,7 +35,7 @@ export const createUndoStack = (map) => {
35
35
  /**
36
36
  * Clear all operations from the stack
37
37
  */
38
- clear() {
38
+ clear () {
39
39
  stack.length = 0
40
40
  fireChange()
41
41
  },
@@ -43,7 +43,7 @@ export const createUndoStack = (map) => {
43
43
  /**
44
44
  * Get current stack length
45
45
  */
46
- get length() {
46
+ get length () {
47
47
  return stack.length
48
48
  }
49
49
  }
@@ -8,7 +8,7 @@
8
8
  * @param {maplibregl.Map} map - Map instance
9
9
  * @returns {MapboxSnap|null} Snap instance or null
10
10
  */
11
- export function getSnapInstance(map) {
11
+ export function getSnapInstance (map) {
12
12
  return map?._snapInstance ?? null
13
13
  }
14
14
 
@@ -17,7 +17,7 @@ export function getSnapInstance(map) {
17
17
  * @param {MapboxSnap} snap - Snap instance
18
18
  * @returns {boolean} True if snap is active with valid coordinates
19
19
  */
20
- export function isSnapActive(snap) {
20
+ export function isSnapActive (snap) {
21
21
  // Also check snap.status to ensure snap feature is enabled
22
22
  return !!(snap?.status && snap?.snapStatus && snap.snapCoords?.length >= 2)
23
23
  }
@@ -27,7 +27,7 @@ export function isSnapActive(snap) {
27
27
  * @param {MapboxSnap} snap - Snap instance
28
28
  * @returns {{ lng: number, lat: number }|null} Snapped coordinates or null
29
29
  */
30
- export function getSnapLngLat(snap) {
30
+ export function getSnapLngLat (snap) {
31
31
  if (!isSnapActive(snap)) {
32
32
  return null
33
33
  }
@@ -42,7 +42,7 @@ export function getSnapLngLat(snap) {
42
42
  * @param {MapboxSnap} snap - Snap instance
43
43
  * @returns {[number, number]|null} Snapped coordinates or null
44
44
  */
45
- export function getSnapCoords(snap) {
45
+ export function getSnapCoords (snap) {
46
46
  if (!isSnapActive(snap)) {
47
47
  return null
48
48
  }
@@ -56,7 +56,7 @@ export function getSnapCoords(snap) {
56
56
  * @param {{ x: number, y: number }} point - Screen point
57
57
  * @returns {boolean} True if snap was triggered
58
58
  */
59
- export function triggerSnapAtPoint(snap, map, point) {
59
+ export function triggerSnapAtPoint (snap, map, point) {
60
60
  if (!snap || !map || !snap.status) {
61
61
  return false
62
62
  }
@@ -72,7 +72,7 @@ export function triggerSnapAtPoint(snap, map, point) {
72
72
  * @param {maplibregl.Map} map - Map instance
73
73
  * @returns {boolean} True if snap was triggered
74
74
  */
75
- export function triggerSnapAtCenter(snap, map) {
75
+ export function triggerSnapAtCenter (snap, map) {
76
76
  // Don't trigger snap if library is disabled
77
77
  if (!snap || !map || !snap.status) {
78
78
  return false
@@ -89,7 +89,7 @@ export function triggerSnapAtCenter(snap, map) {
89
89
  * @param {MapboxSnap} snap - Snap instance
90
90
  * @param {maplibregl.Map} [map] - Optional map instance for direct layer control
91
91
  */
92
- export function clearSnapIndicator(snap, map) {
92
+ export function clearSnapIndicator (snap, map) {
93
93
  if (snap) {
94
94
  snap.snapStatus = false
95
95
  snap.snapCoords = null
@@ -116,7 +116,7 @@ export function clearSnapIndicator(snap, map) {
116
116
  * Clear all snap state (for use between drag operations)
117
117
  * @param {MapboxSnap} snap - Snap instance
118
118
  */
119
- export function clearSnapState(snap) {
119
+ export function clearSnapState (snap) {
120
120
  if (!snap) {
121
121
  return
122
122
  }
@@ -139,7 +139,7 @@ export function clearSnapState(snap) {
139
139
  * @param {MapboxSnap} snap - Snap instance
140
140
  * @returns {number} Snap radius in pixels (default 15)
141
141
  */
142
- export function getSnapRadius(snap) {
142
+ export function getSnapRadius (snap) {
143
143
  return snap?.options?.radius ?? 15
144
144
  }
145
145
 
@@ -148,7 +148,7 @@ export function getSnapRadius(snap) {
148
148
  * @param {object} state - Mode state with optional getSnapEnabled function
149
149
  * @returns {boolean} True if snapping is enabled
150
150
  */
151
- export function isSnapEnabled(state) {
151
+ export function isSnapEnabled (state) {
152
152
  // Only return true if getSnapEnabled exists and explicitly returns true
153
153
  if (typeof state?.getSnapEnabled !== 'function') {
154
154
  return false
@@ -162,7 +162,7 @@ export function isSnapEnabled(state) {
162
162
  * @param {MapboxSnap} snap - Snap instance
163
163
  * @returns {object} Event with snapped lngLat or original event
164
164
  */
165
- export function createSnappedEvent(e, snap) {
165
+ export function createSnappedEvent (e, snap) {
166
166
  const lngLat = getSnapLngLat(snap)
167
167
  if (!lngLat) {
168
168
  return e
@@ -180,7 +180,7 @@ export function createSnappedEvent(e, snap) {
180
180
  * @param {MapboxSnap} snap - Snap instance
181
181
  * @returns {object|null} Synthetic event or null if no snap
182
182
  */
183
- export function createSnappedClickEvent(map, snap) {
183
+ export function createSnappedClickEvent (map, snap) {
184
184
  const lngLat = getSnapLngLat(snap)
185
185
  if (!lngLat) {
186
186
  return null
@@ -28,7 +28,7 @@ import {
28
28
  * @param {Feature<LineString>} line
29
29
  * @param {number} extendDist (distance to extend in Turf units)
30
30
  */
31
- function extendLine(line, extendDist = 1, units = 'meters') {
31
+ function extendLine (line, extendDist = 1, units = 'meters') {
32
32
  const coords = line.geometry.coordinates
33
33
  const result = []
34
34
 
@@ -113,17 +113,17 @@ const toTurfGeometry = (featureOrGeom) => {
113
113
 
114
114
  switch (geom.type) {
115
115
  case 'Polygon':
116
- return turfPolygon(geom.coordinates);
116
+ return turfPolygon(geom.coordinates)
117
117
  case 'MultiPolygon':
118
- return turfMultiPolygon(geom.coordinates);
118
+ return turfMultiPolygon(geom.coordinates)
119
119
  case 'LineString':
120
- return turfLineString(geom.coordinates);
120
+ return turfLineString(geom.coordinates)
121
121
  case 'MultiLineString':
122
- return turfMultiLineString(geom.coordinates);
122
+ return turfMultiLineString(geom.coordinates)
123
123
  case 'Point':
124
- return turfPoint(geom.coordinates);
124
+ return turfPoint(geom.coordinates)
125
125
  case 'MultiPoint':
126
- return turfMultiPoint(geom.coordinates);
126
+ return turfMultiPoint(geom.coordinates)
127
127
  default:
128
128
  throw new Error(`Unsupported geometry type: ${geom.type}`)
129
129
  }
@@ -251,8 +251,8 @@ export {
251
251
  toTurfGeometry,
252
252
  splitPolygon,
253
253
  extendLine,
254
- isNewCoordinate,
255
- isValidClick,
256
- isValidLineClick,
254
+ isNewCoordinate,
255
+ isValidClick,
256
+ isValidLineClick,
257
257
  spatialNavigate
258
- }
258
+ }
@@ -1,7 +1,7 @@
1
1
  import React, { useRef, useEffect, useState } from 'react'
2
2
  import { computeInset } from './utils.js'
3
3
 
4
- export function Frame({ appState, mapState, pluginState, mapProvider }) {
4
+ export function Frame ({ appState, mapState, pluginState, mapProvider }) {
5
5
  const { actionsRef, mainRef, footerRef, viewportRef } = appState.layoutRefs
6
6
  const { dispatch } = pluginState
7
7
  const elRef = useRef(null)
@@ -87,7 +87,7 @@ export function Frame({ appState, mapState, pluginState, mapProvider }) {
87
87
  const viewportRect = viewportEl.getBoundingClientRect()
88
88
 
89
89
  // Calculate padding from viewport edges to frame edges
90
- const scale = {small: 1, medium: 1.5, large: 2}[mapState.mapSize]
90
+ const scale = { small: 1, medium: 1.5, large: 2 }[mapState.mapSize]
91
91
 
92
92
  const padding = {
93
93
  top: (frameRect.top - viewportRect.top) / scale,
@@ -108,11 +108,11 @@ export function Frame({ appState, mapState, pluginState, mapProvider }) {
108
108
  return (
109
109
  <>
110
110
  {/* Spacer */}
111
- <div className="im-c-frame-spacer" style={{ inset: parentInset }} ref={elRef} />
111
+ <div className='im-c-frame-spacer' style={{ inset: parentInset }} ref={elRef} />
112
112
 
113
113
  {/* Child */}
114
114
  {childStyle && (
115
- <div ref={displayRef} className="im-c-frame-display" style={{ ...childStyle }} />
115
+ <div ref={displayRef} className='im-c-frame-display' style={{ ...childStyle }} />
116
116
  )}
117
117
  </>
118
118
  )
@@ -23,8 +23,8 @@ export const FrameInit = ({
23
23
  // Attach events
24
24
  useEffect(() => {
25
25
  if (!isActive) {
26
- return
27
- }
26
+ return
27
+ }
28
28
 
29
29
  // --- Done
30
30
  frameDone.onClick = () => {
@@ -32,7 +32,7 @@ export const FrameInit = ({
32
32
  frameEl: frameRefs.displayRef.current,
33
33
  viewportEl: layoutRefs.viewportRef.current,
34
34
  featureId: frame?.featureId,
35
- scale: {small: 1, medium: 1.5, large: 2}[mapState.mapSize],
35
+ scale: { small: 1, medium: 1.5, large: 2 }[mapState.mapSize],
36
36
  mapProvider
37
37
  })
38
38
 
@@ -51,4 +51,4 @@ export const FrameInit = ({
51
51
  frameCancel.onClick = null
52
52
  }
53
53
  }, [mapState.isMapReady, mode, breakpoint, frame, frameRefs, layoutRefs, mapProvider, dispatch, eventBus, frameDone, frameCancel])
54
- }
54
+ }
@@ -15,4 +15,4 @@ export const addFrame = ({ pluginConfig, pluginState, services }, featureId, con
15
15
  dispatch({ type: 'SET_FRAME', payload: frame })
16
16
 
17
17
  eventBus.emit('frame:add')
18
- }
18
+ }
@@ -24,4 +24,4 @@ export const editFeature = ({ pluginConfig, pluginState, mapProvider, services }
24
24
  dispatch({ type: 'SET_FRAME', payload: { ...frame, bounds } })
25
25
 
26
26
  eventBus.emit('frame:edit')
27
- }
27
+ }
@@ -3,4 +3,4 @@ export const DEFAULT = {
3
3
  mobileWidth: '300px',
4
4
  tabletWidth: '360px',
5
5
  desktopWidth: '400px'
6
- }
6
+ }
@@ -6,8 +6,8 @@ import { addFrame } from './api/addFrame.js'
6
6
  import { editFeature } from './api/editFeature.js'
7
7
 
8
8
  const buttonSlots = {
9
- mobile: { slot: 'actions', showLabel: true },
10
- tablet: { slot: 'actions', showLabel: true },
9
+ mobile: { slot: 'actions', showLabel: true },
10
+ tablet: { slot: 'actions', showLabel: true },
11
11
  desktop: { slot: 'actions', showLabel: true }
12
12
  }
13
13
 
@@ -40,7 +40,7 @@ export const manifest = {
40
40
  variant: 'primary',
41
41
  hiddenWhen: ({ pluginState }) => !pluginState.frame,
42
42
  ...buttonSlots
43
- },{
43
+ }, {
44
44
  id: 'frameCancel',
45
45
  label: 'Cancel',
46
46
  variant: 'tertiary',
@@ -25,4 +25,4 @@ const actions = {
25
25
  export {
26
26
  initialState,
27
27
  actions
28
- }
28
+ }
@@ -132,7 +132,7 @@ function getFeatureAspectRatio (feature, mapProvider) {
132
132
  if (height === 0) {
133
133
  return null
134
134
  }
135
-
135
+
136
136
  // Round to 6 decimal places to account for floating point precision
137
137
  return Math.round((width / height) * 1000000) / 1000000
138
138
  }
@@ -18,14 +18,14 @@ export const MapStyles = ({ mapState, pluginConfig, services, mapProvider }) =>
18
18
  }
19
19
 
20
20
  return (
21
- <div className="im-c-map-styles">
22
- <div className="im-c-map-styles__group">
23
- <div className="im-c-map-styles__inner">
21
+ <div className='im-c-map-styles'>
22
+ <div className='im-c-map-styles__group'>
23
+ <div className='im-c-map-styles__inner'>
24
24
  {mapStyles.filter(mapStyle => mapStyle.url).map(mapStyle => (
25
- <div className="im-c-map-styles__item" key={mapStyle.id}>
26
- <button className="im-c-map-styles__button" aria-pressed={mapStyle.id === currentMapStyle.id} onClick={() => handleMapStyleClick(mapStyle)}>
27
- <div className="im-c-map-styles__image">
28
- <img src={mapStyle.thumbnail || undefined} alt="" height="60" width="60" />
25
+ <div className='im-c-map-styles__item' key={mapStyle.id}>
26
+ <button className='im-c-map-styles__button' aria-pressed={mapStyle.id === currentMapStyle.id} onClick={() => handleMapStyleClick(mapStyle)}>
27
+ <div className='im-c-map-styles__image'>
28
+ <img src={mapStyle.thumbnail || undefined} alt='' height='60' width='60' />
29
29
  </div>
30
30
  {mapStyle.label}
31
31
  </button>
@@ -34,16 +34,16 @@ export const MapStyles = ({ mapState, pluginConfig, services, mapProvider }) =>
34
34
  </div>
35
35
  </div>
36
36
  {supportsMapSizes && (
37
- <div className="im-c-map-styles__group">
38
- <h3 className="im-c-map-styles__heading" id="map-text-sizes">Map size</h3>
39
- <div className="im-c-map-styles__inner">
40
- {["small", "medium", "large"].map(size => (
41
- <div className="im-c-map-styles__item" key={size}>
42
- <button className="im-c-map-styles__button" onClick={() => handleMapSizeClick(size)} aria-pressed={size === currentMapSize}>
43
- <div className="im-c-map-styles__image">
44
- <svg width="60" height="60" viewBox="0 0 60 60" fillRule="evenodd">
45
- <rect className="im-c-map-styles__image-bg" width="100%" height="100%" />
46
- <g style={{ transform: `scale(${scaleFactor[size]})`, transformOrigin: "8px 52px" }}>
37
+ <div className='im-c-map-styles__group'>
38
+ <h3 className='im-c-map-styles__heading' id='map-text-sizes'>Map size</h3>
39
+ <div className='im-c-map-styles__inner'>
40
+ {['small', 'medium', 'large'].map(size => (
41
+ <div className='im-c-map-styles__item' key={size}>
42
+ <button className='im-c-map-styles__button' onClick={() => handleMapSizeClick(size)} aria-pressed={size === currentMapSize}>
43
+ <div className='im-c-map-styles__image'>
44
+ <svg width='60' height='60' viewBox='0 0 60 60' fillRule='evenodd'>
45
+ <rect className='im-c-map-styles__image-bg' width='100%' height='100%' />
46
+ <g style={{ transform: `scale(${scaleFactor[size]})`, transformOrigin: '8px 52px' }}>
47
47
  <path d={textSizeSvgPath} />
48
48
  </g>
49
49
  </svg>
@@ -57,4 +57,4 @@ export const MapStyles = ({ mapState, pluginConfig, services, mapProvider }) =>
57
57
  )}
58
58
  </div>
59
59
  )
60
- }
60
+ }
@@ -23,12 +23,12 @@ export function ScaleBar ({
23
23
  }, [resolution, mapSize, pluginConfig.units])
24
24
 
25
25
  return (
26
- <div className="im-c-scale-bar" ref={elRef} style={{ width: `${scale.width}px` }}>
27
- <span className="im-c-scale-bar__label">
28
- <span className="im-u-visually-hidden">Scale bar: </span>
26
+ <div className='im-c-scale-bar' ref={elRef} style={{ width: `${scale.width}px` }}>
27
+ <span className='im-c-scale-bar__label'>
28
+ <span className='im-u-visually-hidden'>Scale bar: </span>
29
29
  {scale.label}
30
- <span aria-hidden="true">{scale.abbr}</span>
31
- <span className="im-u-visually-hidden">{scale.unit}</span>
30
+ <span aria-hidden='true'>{scale.abbr}</span>
31
+ <span className='im-u-visually-hidden'>{scale.unit}</span>
32
32
  </span>
33
33
  </div>
34
34
  )
@@ -5,7 +5,7 @@ export const UseLocation = ({ pluginState }) => {
5
5
  const { errorMessage } = pluginState
6
6
 
7
7
  return (
8
- <div className="im-c-use-location">
8
+ <div className='im-c-use-location'>
9
9
  <p>{errorMessage}</p>
10
10
  </div>
11
11
  )
@@ -3,4 +3,4 @@ export const errorMessages = {
3
3
  POSITION_UNAVAILABLE: 'Location information is unavailable.',
4
4
  TIMEOUT: 'The location request timed out. Please try again.',
5
5
  FALLBACK: 'Unable to get your location.'
6
- }
6
+ }
@@ -1,6 +1,6 @@
1
1
  import { errorMessages } from './defaults.js'
2
2
 
3
- export function attachEvents({ appState, pluginState, mapProvider, useLocationButton }) {
3
+ export function attachEvents ({ appState, pluginState, mapProvider, useLocationButton }) {
4
4
  const { dispatch: appDispatch, buttonRefs } = appState
5
5
  const { dispatch: pluginDispatch } = pluginState
6
6
 
@@ -30,7 +30,7 @@ export function attachEvents({ appState, pluginState, mapProvider, useLocationBu
30
30
  const message = getFriendlyError(err)
31
31
  const triggeringElement = buttonRefs.current[useLocationButton.id]
32
32
  pluginDispatch({ type: 'SET_ERROR_MESSAGE', payload: message })
33
- appDispatch({ type: 'OPEN_PANEL', payload: { panelId: 'useLocation', props: { triggeringElement }}})
33
+ appDispatch({ type: 'OPEN_PANEL', payload: { panelId: 'useLocation', props: { triggeringElement } } })
34
34
  }, {
35
35
  enableHighAccuracy: true,
36
36
  maximumAge: 0,
@@ -78,4 +78,4 @@ export function attachEvents({ appState, pluginState, mapProvider, useLocationBu
78
78
 
79
79
  // Return helpers in case you want them in future
80
80
  return { startTracking, stopTracking }
81
- }
81
+ }
@@ -24,7 +24,7 @@ export const InteractInit = ({
24
24
  mapState,
25
25
  pluginState,
26
26
  services,
27
- mapProvider,
27
+ mapProvider
28
28
  })
29
29
 
30
30
  // Refs updated synchronously each render — keeps callbacks fresh without re-attaching events
@@ -89,6 +89,5 @@ export const InteractInit = ({
89
89
  return cleanupEvents
90
90
  }, [pluginState.enabled, buttonConfig, events, eventBus, closeApp])
91
91
 
92
-
93
92
  return null
94
93
  }
@@ -7,9 +7,12 @@
7
7
  import { DEFAULTS } from '../defaults.js'
8
8
 
9
9
  export const enable = ({ pluginState, pluginConfig }, options) => {
10
- pluginState.dispatch({ type: 'ENABLE', payload: {
11
- ...DEFAULTS,
12
- ...pluginConfig,
13
- ...options
14
- }})
10
+ pluginState.dispatch({
11
+ type: 'ENABLE',
12
+ payload: {
13
+ ...DEFAULTS,
14
+ ...pluginConfig,
15
+ ...options
16
+ }
17
+ })
15
18
  }
@@ -18,9 +18,9 @@ describe('enable', () => {
18
18
  expect(dispatch).toHaveBeenCalledWith({
19
19
  type: 'ENABLE',
20
20
  payload: expect.objectContaining({
21
- interactionMode: 'select', // options override DEFAULTS
21
+ interactionMode: 'select', // options override DEFAULTS
22
22
  multiSelect: DEFAULTS.multiSelect, // default preserved
23
- markerColor: 'green', // options override pluginConfig
23
+ markerColor: 'green', // options override pluginConfig
24
24
  dataLayers: [{ layerId: 'test' }] // options passed
25
25
  })
26
26
  })
@@ -6,8 +6,8 @@
6
6
  */
7
7
  export const selectFeature = ({ services }, { featureId, layerId, idProperty }) => {
8
8
  services.eventBus.emit('interact:selectFeature', {
9
- featureId,
10
- layerId,
11
- idProperty
12
- })
9
+ featureId,
10
+ layerId,
11
+ idProperty
12
+ })
13
13
  }
@@ -6,8 +6,8 @@
6
6
  */
7
7
  export const unselectFeature = ({ services }, { featureId, layerId, idProperty }) => {
8
8
  services.eventBus.emit('interact:unselectFeature', {
9
- featureId,
10
- layerId,
11
- idProperty
12
- })
13
- }
9
+ featureId,
10
+ layerId,
11
+ idProperty
12
+ })
13
+ }
@@ -9,4 +9,3 @@ export const DEFAULTS = {
9
9
  selectedFill: 'rgba(255, 0, 0, 0.1)',
10
10
  selectedStrokeWidth: 2
11
11
  }
12
-
@@ -18,7 +18,7 @@ describe('attachEvents', () => {
18
18
  getPluginState: () => pluginState,
19
19
  mapState: {
20
20
  markers: { remove: jest.fn(), getMarker: jest.fn(() => null) },
21
- crossHair: { getDetail: jest.fn(() => ({ point: { x: 0, y: 0 }, coords: [0,0] })) }
21
+ crossHair: { getDetail: jest.fn(() => ({ point: { x: 0, y: 0 }, coords: [0, 0] })) }
22
22
  },
23
23
  buttonConfig: { selectDone: {}, selectAtTarget: {}, selectCancel: {} },
24
24
  events: { MAP_CLICK: 'map:click' },
@@ -78,10 +78,10 @@ describe('attachEvents', () => {
78
78
  params.clickReadyRef.current = true
79
79
  cleanup = attachEvents(params)
80
80
 
81
- const handler = params.eventBus.on.mock.calls.find(c => c[0]==='map:click')[1]
82
- handler({ point:{x:1,y:2}, coords:[3,4] })
81
+ const handler = params.eventBus.on.mock.calls.find(c => c[0] === 'map:click')[1]
82
+ handler({ point: { x: 1, y: 2 }, coords: [3, 4] })
83
83
 
84
- expect(params.handleInteraction).toHaveBeenCalledWith({ point:{x:1,y:2}, coords:[3,4] })
84
+ expect(params.handleInteraction).toHaveBeenCalledWith({ point: { x: 1, y: 2 }, coords: [3, 4] })
85
85
  })
86
86
 
87
87
  it('map click is suppressed when clickReadyRef is false', () => {
@@ -89,8 +89,8 @@ describe('attachEvents', () => {
89
89
  params.clickReadyRef.current = false
90
90
  cleanup = attachEvents(params)
91
91
 
92
- const handler = params.eventBus.on.mock.calls.find(c => c[0]==='map:click')[1]
93
- handler({ point:{x:1,y:2}, coords:[3,4] })
92
+ const handler = params.eventBus.on.mock.calls.find(c => c[0] === 'map:click')[1]
93
+ handler({ point: { x: 1, y: 2 }, coords: [3, 4] })
94
94
 
95
95
  expect(params.handleInteraction).not.toHaveBeenCalled()
96
96
  })
@@ -99,7 +99,7 @@ describe('attachEvents', () => {
99
99
  const params = createParams()
100
100
  cleanup = attachEvents(params)
101
101
 
102
- const crossDetail = { point:{x:1,y:2}, coords:[3,4] }
102
+ const crossDetail = { point: { x: 1, y: 2 }, coords: [3, 4] }
103
103
  params.mapState.crossHair.getDetail.mockReturnValue(crossDetail)
104
104
 
105
105
  params.buttonConfig.selectAtTarget.onClick()
@@ -111,14 +111,14 @@ describe('attachEvents', () => {
111
111
  cleanup = attachEvents(params)
112
112
 
113
113
  // closeOnAction = true (already covered)
114
- params.mapState.markers.getMarker.mockReturnValue({ coords:[1,2] })
114
+ params.mapState.markers.getMarker.mockReturnValue({ coords: [1, 2] })
115
115
  params.buttonConfig.selectDone.onClick()
116
116
  expect(params.closeApp).toHaveBeenCalled()
117
117
 
118
118
  // cover closeOnAction = false
119
119
  params.closeApp.mockClear()
120
120
  params.pluginState.closeOnAction = false
121
- params.mapState.markers.getMarker.mockReturnValue({ coords:[3,4] })
121
+ params.mapState.markers.getMarker.mockReturnValue({ coords: [3, 4] })
122
122
  params.buttonConfig.selectDone.onClick()
123
123
  expect(params.closeApp).not.toHaveBeenCalled()
124
124
  })
@@ -155,11 +155,11 @@ describe('attachEvents', () => {
155
155
  const params = createParams()
156
156
  cleanup = attachEvents(params)
157
157
 
158
- const selectHandler = params.eventBus.on.mock.calls.find(c => c[0]==='interact:selectFeature')[1]
159
- const unselectHandler = params.eventBus.on.mock.calls.find(c => c[0]==='interact:unselectFeature')[1]
158
+ const selectHandler = params.eventBus.on.mock.calls.find(c => c[0] === 'interact:selectFeature')[1]
159
+ const unselectHandler = params.eventBus.on.mock.calls.find(c => c[0] === 'interact:unselectFeature')[1]
160
160
 
161
- selectHandler({ featureId:'F1' })
162
- unselectHandler({ featureId:'F2' })
161
+ selectHandler({ featureId: 'F1' })
162
+ unselectHandler({ featureId: 'F2' })
163
163
 
164
164
  expect(params.pluginState.dispatch).toHaveBeenCalledTimes(2)
165
165
  expect(params.mapState.markers.remove).toHaveBeenCalledTimes(2)
@@ -178,7 +178,7 @@ describe('attachEvents', () => {
178
178
 
179
179
  // Ensure marker returns null (no coords)
180
180
  params.mapState.markers.getMarker.mockReturnValue(null)
181
-
181
+
182
182
  // Set up features and bounds
183
183
  params.pluginState.selectedFeatures = [{ id: 'f1' }]
184
184
  params.pluginState.selectionBounds = { sw: [0, 0], ne: [1, 1] }
@@ -194,7 +194,7 @@ describe('attachEvents', () => {
194
194
  it('respects default closeOnAction when value is undefined (fallback to true)', () => {
195
195
  const params = createParams()
196
196
  // Explicitly set to undefined to trigger the ?? fallback
197
- params.pluginState.closeOnAction = undefined
197
+ params.pluginState.closeOnAction = undefined
198
198
  cleanup = attachEvents(params)
199
199
 
200
200
  // Test for selectDone
@@ -45,4 +45,4 @@ export const useHighlightSync = ({
45
45
  eventBus.off(events.MAP_DATA_CHANGE, updateHighlightedFeatures)
46
46
  }
47
47
  }, [selectedFeatures, mapProvider, stylesMap])
48
- }
48
+ }
@@ -34,7 +34,7 @@ export const useInteractionHandlers = ({
34
34
  mapState,
35
35
  pluginState,
36
36
  services,
37
- mapProvider,
37
+ mapProvider
38
38
  }) => {
39
39
  const { markers } = mapState
40
40
  const { dispatch, dataLayers, interactionMode, multiSelect, contiguous, markerColor, tolerance, selectedFeatures, selectionBounds, deselectOnClickOutside } = pluginState
@@ -71,7 +71,7 @@ export const useInteractionHandlers = ({
71
71
  }
72
72
 
73
73
  // Internal helper to keep complexity low
74
- function processFeatureMatch({ feature, config }) {
74
+ function processFeatureMatch ({ feature, config }) {
75
75
  markers.remove('location')
76
76
  const isNewContiguous = contiguous && isContiguousWithAny(feature, selectedFeatures)
77
77
  const featureId = feature.properties?.[config.idProperty] ?? feature.id
@@ -295,7 +295,7 @@ it('emits selectionchange once when bounds exist', () => {
295
295
 
296
296
  it('skips emission when selection remains empty after being cleared', () => {
297
297
  const eventBus = { emit: jest.fn() }
298
-
298
+
299
299
  // 1. First render with a feature (prev is null, emission happens)
300
300
  const { rerender } = renderHook(
301
301
  ({ features }) => useInteractionHandlers({
@@ -306,7 +306,7 @@ it('skips emission when selection remains empty after being cleared', () => {
306
306
  }),
307
307
  { initialProps: { features: [{ id: 'f1' }] } }
308
308
  )
309
-
309
+
310
310
  expect(eventBus.emit).toHaveBeenCalledTimes(1)
311
311
  eventBus.emit.mockClear()
312
312
 
@@ -315,11 +315,11 @@ it('skips emission when selection remains empty after being cleared', () => {
315
315
  expect(eventBus.emit).toHaveBeenCalledTimes(1)
316
316
  eventBus.emit.mockClear()
317
317
 
318
- // 3. Rerender with empty selection AGAIN
318
+ // 3. Rerender with empty selection AGAIN
319
319
  // This triggers: prev !== null AND prev.length === 0
320
320
  rerender({ features: [] })
321
-
322
- // Should skip emission because wasEmpty is true (via prev.length === 0)
321
+
322
+ // Should skip emission because wasEmpty is true (via prev.length === 0)
323
323
  // and current features.length is 0
324
324
  expect(eventBus.emit).not.toHaveBeenCalled()
325
325
  })