@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
@@ -1,25 +1,20 @@
1
1
  # Search Plugin
2
2
 
3
- Location search plugin with autocomplete functionality. Supports custom datasets for searching locations, addresses, or other geographic features.
3
+ Location search with autocomplete. Supports the OS Names API out of the box, and can be extended with custom datasets for searching addresses, features, or other geographic data.
4
4
 
5
5
  ## Usage
6
6
 
7
7
  ```js
8
- import createSearchPlugin from '@defra/interactive-map/plugins/search'
9
-
10
- const searchPlugin = createSearchPlugin({
11
- showMarker: true,
12
- datasets: [
13
- {
14
- id: 'os-places',
15
- url: '/api/search',
16
- minChars: 3
17
- }
18
- ]
19
- })
8
+ import searchPlugin from '@defra/interactive-map/plugins/search'
20
9
 
21
10
  const interactiveMap = new InteractiveMap({
22
- plugins: [searchPlugin]
11
+ plugins: [
12
+ searchPlugin({
13
+ osNamesURL: process.env.OS_NAMES_URL,
14
+ transformRequest: transformGeocodeRequest,
15
+ showMarker: true
16
+ })
17
+ ]
23
18
  })
24
19
  ```
25
20
 
@@ -29,48 +24,94 @@ Options are passed to the factory function when creating the plugin.
29
24
 
30
25
  ---
31
26
 
32
- ### `showMarker`
33
- **Type:** `boolean`
34
- **Default:** `true`
27
+ ### `osNamesURL`
28
+ **Type:** `string`
35
29
 
36
- Whether to display a marker at the selected location.
30
+ URL for the OS Names API, with a `{query}` placeholder. When provided, the plugin uses this as the primary search source.
31
+
32
+ ```js
33
+ searchPlugin({
34
+ osNamesURL: 'https://api.os.uk/search/names/v1/find?query={query}&key=YOUR_KEY'
35
+ })
36
+ ```
37
37
 
38
38
  ---
39
39
 
40
- ### `datasets`
41
- **Type:** `SearchDataset[]`
40
+ ### `transformRequest`
41
+ **Type:** `Function`
42
42
 
43
- Array of dataset configurations for search. Each dataset defines a source for search suggestions.
43
+ Async function called before each search request is sent. Use this to add authentication headers or modify the request. Receives the default request config and the query string, and should return a (modified) request config.
44
44
 
45
45
  ```js
46
- createSearchPlugin({
47
- datasets: [
48
- {
49
- id: 'os-places',
50
- url: '/api/os-places/search',
51
- minChars: 3,
52
- params: {
53
- maxResults: 10
54
- }
55
- }
56
- ]
46
+ searchPlugin({
47
+ transformRequest: async (request, query) => ({
48
+ ...request,
49
+ headers: { Authorization: `Bearer ${token}` }
50
+ })
51
+ })
52
+ ```
53
+
54
+ ---
55
+
56
+ ### `regions`
57
+ **Type:** `string[]`
58
+ **Default:** `['england', 'scotland', 'wales']`
59
+
60
+ Filters OS Names results to the specified UK regions. Values are matched case-insensitively against the country field in OS Names results.
61
+
62
+ ```js
63
+ searchPlugin({
64
+ regions: ['england', 'wales']
65
+ })
66
+ ```
67
+
68
+ ---
69
+
70
+ ### `customDatasets`
71
+ **Type:** `CustomDataset[]`
72
+
73
+ Array of custom dataset configurations to extend or replace the built-in OS Names search. Each dataset defines how to fetch and parse results for a particular type of query.
74
+
75
+ See [Custom datasets](#custom-datasets) below for full details.
76
+
77
+ ```js
78
+ searchPlugin({
79
+ customDatasets: [gridRefDataset, parcelDataset]
57
80
  })
58
81
  ```
59
82
 
60
83
  ---
61
84
 
62
- ### `isExpanded`
85
+ ### `showMarker`
63
86
  **Type:** `boolean`
64
- **Default:** `false`
87
+ **Default:** `true`
65
88
 
66
- Whether the search input is initially expanded on mobile devices.
89
+ Whether to place a marker on the map when a search result is selected.
67
90
 
68
91
  ---
69
92
 
70
93
  ### `markerColor`
71
94
  **Type:** `string`
72
95
 
73
- Colour of the search result marker. Overrides the default `markerColor` option.
96
+ Colour of the search result marker.
97
+
98
+ ---
99
+
100
+ ### `width`
101
+ **Type:** `string`
102
+
103
+ CSS width of the search input on tablet and desktop. For example `'300px'`.
104
+
105
+ ---
106
+
107
+ ### `expanded`
108
+ **Type:** `boolean`
109
+ **Default:** `false`
110
+
111
+ Controls whether the search input is always visible or hidden behind an open button.
112
+
113
+ - **Mobile** — by default the search is hidden and requires a button tap to open. When `expanded: true`, it moves to the banner slot and is shown inline at the top of the map at all times.
114
+ - **Tablet and desktop** — the search always sits in the `top-left` slot regardless of this setting, but setting `expanded: true` removes the open button so the input is immediately visible without interaction.
74
115
 
75
116
  ---
76
117
 
@@ -88,10 +129,117 @@ Array of mode identifiers. When set, the plugin does not render when the app is
88
129
 
89
130
  ---
90
131
 
132
+ ## Custom datasets
133
+
134
+ Custom datasets let you add your own search sources alongside or instead of OS Names. Pass them via the `customDatasets` option as an array of dataset configuration objects.
135
+
136
+ ```js
137
+ const gridRefDataset = {
138
+ name: 'gridref',
139
+ includeRegex: /^[A-Z]{2}\d{6,10}$/i,
140
+ buildRequest: (query) => `https://api.example.com/gridref?q=${query}`,
141
+ parseResults: (json, query) => [{
142
+ id: query,
143
+ text: query,
144
+ marked: `<mark>${query}</mark> (Grid reference)`,
145
+ point: [json.lon, json.lat],
146
+ bounds: [json.minLon, json.minLat, json.maxLon, json.maxLat],
147
+ type: 'gridref'
148
+ }]
149
+ }
150
+
151
+ searchPlugin({
152
+ customDatasets: [gridRefDataset]
153
+ })
154
+ ```
155
+
156
+ ### `CustomDataset` properties
157
+
158
+ ---
159
+
160
+ #### `name`
161
+ **Type:** `string`
162
+ **Required**
163
+
164
+ Unique identifier for the dataset. Included as the `type` property in the `search:match` event payload, which lets you distinguish between results from different datasets.
165
+
166
+ ---
167
+
168
+ #### `buildRequest`
169
+ **Type:** `Function`
170
+
171
+ Function that takes the search query and returns a URL string or a `{ url, options }` fetch config object. Use this when you need custom URL construction or fetch options.
172
+
173
+ If omitted, `urlTemplate` is used instead.
174
+
175
+ ```js
176
+ buildRequest: (query) => ({
177
+ url: `https://api.example.com/search?q=${encodeURIComponent(query)}`,
178
+ options: { headers: { Accept: 'application/json' } }
179
+ })
180
+ ```
181
+
182
+ ---
183
+
184
+ #### `urlTemplate`
185
+ **Type:** `string`
186
+
187
+ URL template with a `{query}` placeholder. A simpler alternative to `buildRequest` for straightforward GET requests.
188
+
189
+ ```js
190
+ urlTemplate: 'https://api.example.com/search?q={query}'
191
+ ```
192
+
193
+ ---
194
+
195
+ #### `parseResults`
196
+ **Type:** `Function`
197
+ **Required**
198
+
199
+ Function that receives the parsed JSON response and the original query string, and returns an array of suggestion objects. Return an empty array if there are no results.
200
+
201
+ Each suggestion object must have:
202
+
203
+ | Property | Type | Description |
204
+ |----------|------|-------------|
205
+ | `id` | `string` | Unique identifier for the suggestion |
206
+ | `text` | `string` | Display text shown in the autocomplete list |
207
+ | `marked` | `string` | Optional. HTML string with query terms wrapped in `<mark>` tags. If omitted, the suggestion label will be blank |
208
+ | `point` | `[x, y]` | Centre coordinate for placing a marker |
209
+ | `bounds` | `[minX, minY, maxX, maxY]` | Bounding box to fit the map to when selected |
210
+ | `type` | `string` | Optional. Value to include in the `search:match` payload to identify the source dataset |
211
+
212
+ Any additional properties on the suggestion object are passed through in the `search:match` event payload.
213
+
214
+ ---
215
+
216
+ #### `includeRegex`
217
+ **Type:** `RegExp`
218
+
219
+ If provided, the dataset is only queried when the input matches this pattern. Useful for datasets that only apply to specific input formats (e.g. grid references, parcel IDs).
220
+
221
+ ---
222
+
223
+ #### `excludeRegex`
224
+ **Type:** `RegExp`
225
+
226
+ If provided, the dataset is skipped when the input matches this pattern.
227
+
228
+ ---
229
+
230
+ #### `exclusive`
231
+ **Type:** `boolean`
232
+
233
+ When `true`, if this dataset returns results no other datasets will be queried. Useful for high-confidence lookups where you want to suppress the OS Names fallback.
234
+
235
+ ---
236
+
91
237
  ## Methods
92
238
 
93
239
  This plugin does not expose any public methods.
94
240
 
241
+ ---
242
+
95
243
  ## Events
96
244
 
97
245
  Subscribe to events using `interactiveMap.on()`.
@@ -100,63 +248,59 @@ Subscribe to events using `interactiveMap.on()`.
100
248
 
101
249
  ### `search:match`
102
250
 
103
- Emitted when a search result is selected.
251
+ Emitted when the user selects a search result.
104
252
 
105
253
  **Payload:**
254
+
255
+ The full suggestion object returned by the dataset's `parseResults` function, plus the original `query` string. At minimum:
256
+
106
257
  ```js
107
258
  {
108
- query: 'London',
109
- text: 'London, Greater London',
259
+ query: 'NY7019', // The original search input
260
+ id: '...',
261
+ text: 'NY 701 924',
262
+ marked: '<mark>NY 701 924</mark> (Grid reference)',
110
263
  point: [lng, lat],
111
- bounds: [west, south, east, north]
264
+ bounds: [west, south, east, north],
265
+ type: 'gridref' // The dataset name, useful for distinguishing result types
266
+ // ...any other properties returned by parseResults
112
267
  }
113
268
  ```
114
269
 
115
270
  ```js
116
- interactiveMap.on('search:match', ({ query, point, bounds }) => {
117
- console.log('Location selected:', query)
118
- console.log('Coordinates:', point)
271
+ interactiveMap.on('search:match', (e) => {
272
+ if (e.type === 'parcel') {
273
+ interactPlugin.selectFeature({ featureId: e.properties.id, layerId: 'parcels' })
274
+ }
119
275
  })
120
276
  ```
121
277
 
122
278
  ---
123
279
 
124
- ### `search:open`
280
+ ### `search:clear`
125
281
 
126
- Emitted when the search input is expanded (mobile only).
282
+ Emitted when the search input is cleared.
127
283
 
128
284
  **Payload:** None
129
285
 
130
286
  ```js
131
- interactiveMap.on('search:open', () => {
132
- console.log('Search opened')
287
+ interactiveMap.on('search:clear', () => {
288
+ interactPlugin.unselectFeature({ featureId: selectedId })
133
289
  })
134
290
  ```
135
291
 
136
292
  ---
137
293
 
138
- ### `search:close`
294
+ ### `search:open`
139
295
 
140
- Emitted when the search input is collapsed or dismissed.
296
+ Emitted when the open button is clicked to expand the search. Only applies when `expanded` is `false`, as that is the only case where an open button is rendered.
141
297
 
142
298
  **Payload:** None
143
299
 
144
- ```js
145
- interactiveMap.on('search:close', () => {
146
- console.log('Search closed')
147
- })
148
- ```
149
-
150
300
  ---
151
301
 
152
- ### `search:clear`
302
+ ### `search:close`
153
303
 
154
- Emitted when the search input is cleared.
304
+ Emitted when the search is dismissed — via the close button, a click outside the search, or (on mobile only) after a suggestion is selected or the form is submitted.
155
305
 
156
306
  **Payload:** None
157
-
158
- ```js
159
- interactiveMap.on('search:clear', () => {
160
- console.log('Search cleared')
161
- })
162
- ```
package/docs/plugins.md CHANGED
@@ -4,7 +4,7 @@ Plugins extend the InteractiveMap with additional functionality. This page lists
4
4
 
5
5
  For guidance on building your own plugins, see [Building a Plugin](./building-a-plugin.md).
6
6
 
7
- ## Available Plugins
7
+ ## Available plugins
8
8
 
9
9
  The following plugins are available for use with InteractiveMap.
10
10
 
@@ -24,17 +24,17 @@ Scale bar display plugin that shows the current map scale.
24
24
 
25
25
  Location search plugin with autocomplete functionality. Include custom datasets to search.
26
26
 
27
- ## Alpha Plugins
27
+ ## Coming soon
28
28
 
29
29
  The following plugins are in early development. APIs and features may change.
30
30
 
31
- ### Datasets
31
+ ### [Datasets](./plugins/datasets.md)
32
32
 
33
33
  Add datasets to your map, configure the display, layer toggling and render a key of symbology.
34
34
 
35
35
  ### Draw for MapLibre
36
36
 
37
- Draw lines and polygons using the MapLibre map provider.
37
+ Draw lines, polygons and place points using the MapLibre map provider. Includes geometry actions such as split and merge.
38
38
 
39
39
  ### Draw for ESRI SDK
40
40
 
@@ -48,15 +48,7 @@ Add a regular shaped frame to the map and control its position. Use to generate
48
48
 
49
49
  Geolocation plugin that allows users to centre the map on their current location.
50
50
 
51
- ## Coming Soon
52
-
53
- The following plugins are planned for future releases.
54
-
55
- ### Geometry Actions
56
-
57
- Split and merge polygons.
58
-
59
- ## Using Plugins
51
+ ## Using plugins
60
52
 
61
53
  Plugins are registered via the `plugins` option when creating an InteractiveMap. Plugins typically export a factory function that accepts configuration options:
62
54
 
@@ -80,7 +72,7 @@ The factory function returns a [PluginDescriptor](./plugins/plugin-descriptor.md
80
72
  - **load** - Function that returns a [PluginManifest](./plugins/plugin-manifest.md)
81
73
  - **...options** - Configuration passed to the factory, available as [pluginConfig](./plugins/plugin-context.md#pluginconfig)
82
74
 
83
- ## Plugin Events
75
+ ## Plugin events
84
76
 
85
77
  Plugins can emit events that you can listen to using `interactiveMap.on()`:
86
78
 
@@ -94,7 +86,7 @@ interactiveMap.on('highlight:removed', ({ id }) => {
94
86
  })
95
87
  ```
96
88
 
97
- ## Plugin Methods
89
+ ## Plugin methods
98
90
 
99
91
  Plugins can expose methods that you call on the plugin instance:
100
92
 
@@ -108,7 +100,7 @@ interactiveMap.on('map:ready', () => {
108
100
 
109
101
  See individual plugin documentation for available events and methods.
110
102
 
111
- ## Further Reading
103
+ ## Further reading
112
104
 
113
105
  - [Building a Plugin](./building-a-plugin.md) - Guide to creating custom plugins
114
106
  - [PluginDescriptor](./plugins/plugin-descriptor.md) - Plugin registration reference
@@ -3,9 +3,9 @@
3
3
  /** @type {import('@docusaurus/types').Config} */
4
4
  const config = {
5
5
  staticDirectories: ['assets'],
6
- title: 'Interactive Map',
6
+ title: 'Defra Interactive Map',
7
7
  tagline: 'An accessibility-first interactive map component for government frontends',
8
- favicon: 'images/favicon.ico',
8
+ favicon: 'images/favicon.svg',
9
9
 
10
10
  url: 'https://defra.github.io',
11
11
  baseUrl: '/interactive-map/',
@@ -41,6 +41,14 @@ const config = {
41
41
  ],
42
42
 
43
43
  plugins: [
44
+ function customCssPlugin() {
45
+ return {
46
+ name: 'custom-css',
47
+ getClientModules() {
48
+ return [require.resolve('./assets/css/docusaurus.css')];
49
+ },
50
+ };
51
+ },
44
52
  [
45
53
  '@docusaurus/plugin-content-docs',
46
54
  {
@@ -66,18 +74,17 @@ const config = {
66
74
  },
67
75
 
68
76
  navigation: [
69
- { text: 'Getting Started', href: '/getting-started' },
70
- { text: 'Demo', href: '/demo', sidebar: 'auto' },
71
77
  {
72
- text: 'Architecture',
73
- href: '/architecture',
78
+ text: 'Getting Started',
79
+ href: '/getting-started',
74
80
  sidebar: [
75
- { text: 'Overview', href: '/architecture' },
76
- { text: 'Diagrams', href: 'architecture-diagrams' },
77
- { text: 'Diagram Viewer', href: 'diagrams-viewer' },
81
+ { text: 'Installation', href: '/getting-started#installation' },
82
+ { text: 'Basic usage', href: '/getting-started#basic-usage' },
83
+ { text: 'Using plugins', href: '/getting-started#using-plugins' },
84
+ { text: 'GOV.UK Prototype kit', href: '/getting-started#govuk-prototype-kit-plugin' }
78
85
  ],
79
86
  },
80
- { text: 'GOV.UK Prototype', href: '/govuk-prototype' },
87
+ { text: 'Examples', href: '/examples', sidebar: 'auto' },
81
88
  {
82
89
  text: 'API',
83
90
  href: '/api',
@@ -87,31 +94,24 @@ const config = {
87
94
  text: 'Plugins',
88
95
  href: '/plugins',
89
96
  sidebar: [
90
- { text: 'Overview', href: '/plugins' },
91
- { text: 'Building a Plugin', href: '/building-a-plugin' },
92
- {
93
- text: 'Available Plugins',
94
- href: '/plugins#available-plugins',
95
- items: [
96
- { text: 'Interact', href: '/plugins#interact' },
97
- { text: 'Map Styles', href: '/plugins#map-styles' },
98
- { text: 'Scale Bar', href: '/plugins#scale-bar' },
99
- { text: 'Search', href: '/plugins#search' },
100
- ],
101
- },
102
- {
103
- text: 'Alpha Plugins',
104
- href: '/plugins#alpha-plugins',
105
- items: [
106
- { text: 'Datasets', href: '/plugins#datasets' },
107
- { text: 'Draw for MapLibre', href: '/plugins#draw-for-maplibre' },
108
- { text: 'Draw for ESRI SDK', href: '/plugins#draw-for-esri-sdk' },
109
- { text: 'Frame', href: '/plugins#frame' },
110
- { text: 'Use Location', href: '/plugins#use-location' },
111
- ],
112
- },
97
+ // { text: 'Overview', href: '/plugins' },
98
+ // { text: 'Building a Plugin', href: '/building-a-plugin' },
99
+ { text: 'Available Plugins', href: '/plugins#available-plugins' },
100
+ { text: 'Coming soon', href: '/plugins#coming-soon' },
101
+ { text: 'Using plugins', href: '/plugins#using-plugins' },
102
+ { text: 'Plugin events', href: '/plugins#plugin-events' },
103
+ { text: 'Plugin methods', href: '/plugins#plugin-methods' },
104
+ { text: 'Further reading', href: '/plugins#further-reading' },
113
105
  ],
114
106
  },
107
+ {
108
+ text: 'Architecture',
109
+ href: '/architecture',
110
+ sidebar: [
111
+ { text: 'Diagrams', href: 'architecture-diagrams' },
112
+ { text: 'Diagram Viewer', href: 'diagrams-viewer' },
113
+ ],
114
+ }
115
115
  ],
116
116
 
117
117
  phaseBanner: {
@@ -127,7 +127,7 @@ const config = {
127
127
 
128
128
  homepage: {
129
129
  getStartedHref: '/getting-started',
130
- description: 'A lightweight, accessible map component for public-facing government services. Open source, multi-engine, and extendable through plugins.',
130
+ description: 'Built for developers creating public-facing services on GOV.UK. Takes care of the hard work of building an accessible, standards-compliant mapping interface, so you can focus on your data.',
131
131
  },
132
132
  },
133
133
  },
package/jest.setup.js CHANGED
@@ -15,4 +15,4 @@ if (!window.matchMedia) {
15
15
  dispatchEvent: jest.fn()
16
16
  }))
17
17
  })
18
- }
18
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra/interactive-map",
3
- "version": "0.0.15-alpha",
3
+ "version": "0.0.17-alpha",
4
4
  "description": "An accessible map component",
5
5
  "repository": {
6
6
  "type": "git",
@@ -86,10 +86,10 @@
86
86
  "build": "npm run clean && npm-run-all --parallel build:umd build:esm",
87
87
  "type-check": "tsc --noEmit",
88
88
  "lint": "npm run lint:js && npm run lint:scss",
89
- "lint:js": "standard \"src/**/*.{js,jsx,ts,tsx}\"",
89
+ "lint:js": "standard \"./**/*.{js,jsx,ts,tsx}\"",
90
90
  "lint:scss": "stylelint \"src/**/*.{css,scss}\"",
91
91
  "lint:fix": "npm run lint:js:fix && npm run lint:scss:fix",
92
- "lint:js:fix": "standard \"src/**/*.{js,jsx,ts,tsx}\" --fix",
92
+ "lint:js:fix": "standard \"./**/*.{js,jsx,ts,tsx}\" --fix",
93
93
  "lint:scss:fix": "stylelint \"src/**/*.{css,scss}\" --fix",
94
94
  "test": "jest --color --coverage --verbose",
95
95
  "report": "webpack --profile --json --config webpack.prod.mjs > stats.json && webpack-bundle-analyzer --host 0.0.0.0 --port 8888 ./stats.json ./public",
@@ -127,7 +127,7 @@
127
127
  "@babel/plugin-transform-runtime": "^7.29.0",
128
128
  "@babel/preset-env": "^7.28.0",
129
129
  "@babel/preset-react": "^7.27.1",
130
- "@defra/docusaurus-theme-govuk": "^0.0.12-alpha",
130
+ "@defra/docusaurus-theme-govuk": "^0.0.16-alpha",
131
131
  "@docusaurus/core": "^3.9.2",
132
132
  "@docusaurus/module-type-aliases": "^3.9.2",
133
133
  "@docusaurus/plugin-content-docs": "^3.9.2",
@@ -156,6 +156,7 @@
156
156
  "geodesy": "^2.4.0",
157
157
  "jest": "^29.7.0",
158
158
  "jest-environment-jsdom": "^30.0.4",
159
+ "jest-expect-message": "^1.1.3",
159
160
  "likec4": "^1.50.0",
160
161
  "mapbox-gl-snap": "^1.1.9",
161
162
  "mini-css-extract-plugin": "^2.9.2",
@@ -217,7 +218,7 @@
217
218
  "@turf/polygon-to-line": "^7.3.3",
218
219
  "accessible-autocomplete": "^3.0.1",
219
220
  "govuk-frontend": "^5.13.0",
220
- "maplibre-gl": "^5.15.0",
221
+ "maplibre-gl": "^5.21.1",
221
222
  "polygon-splitter": "^0.0.11",
222
223
  "preact": "^10.27.2",
223
224
  "tslib": "^2.8.1"