@defra/interactive-map 0.0.31-alpha → 0.0.33-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 (131) hide show
  1. package/README.md +2 -2
  2. package/assets/images/bright-ofm-thumb.jpg +0 -0
  3. package/assets/images/dark-ofm-thumb.jpg +0 -0
  4. package/assets/images/road-ofm-thumb.jpg +0 -0
  5. package/assets/templates/add-polygons.njk +143 -0
  6. package/assets/templates/add-symbols.njk +119 -0
  7. package/assets/templates/{map.njk → basic-map.njk} +9 -17
  8. package/assets/templates/button-map.njk +56 -0
  9. package/assets/templates/draw-tools.njk +161 -0
  10. package/assets/templates/marker-panel.njk +91 -0
  11. package/assets/templates/place-marker.njk +104 -0
  12. package/assets/templates/search-control.njk +98 -0
  13. package/assets/templates/select-feature.njk +101 -0
  14. package/assets/templates/style-switcher.njk +87 -0
  15. package/assets/templates/toggle-marker-label.njk +74 -0
  16. package/dist/css/index.css +1 -1
  17. package/dist/esm/im-core.js +1 -1
  18. package/dist/esm/im-shell.js +1 -1
  19. package/dist/umd/im-core.js +1 -1
  20. package/dist/umd/index.js +1 -1
  21. package/docs/api/map-style-config.md +27 -3
  22. package/docs/api.md +55 -0
  23. package/docs/assets/css/docusaurus.scss +22 -6
  24. package/docs/assets/images/add-polygons.jpg +0 -0
  25. package/docs/assets/images/add-symbols.jpg +0 -0
  26. package/docs/assets/images/hero.png +0 -0
  27. package/docs/assets/images/place-marker.jpg +0 -0
  28. package/docs/assets/images/screenshot.jpg +0 -0
  29. package/docs/examples/add-marker-with-panel.mdx +1 -1
  30. package/docs/examples/add-polygons.mdx +225 -0
  31. package/docs/examples/add-symbols.mdx +177 -0
  32. package/docs/examples/{draw.mdx → draw-tools.mdx} +2 -2
  33. package/docs/examples/index.mdx +38 -2
  34. package/docs/examples/place-marker.mdx +151 -0
  35. package/docs/plugins/datasets.md +144 -96
  36. package/docs/plugins/interact.md +1 -4
  37. package/docusaurus.config.cjs +5 -2
  38. package/govuk-prototype-kit.config.json +52 -2
  39. package/package.json +1 -1
  40. package/plugins/beta/datasets/dist/css/index.css +1 -2
  41. package/plugins/beta/datasets/dist/esm/im-datasets-ml-adapter.js +1 -1
  42. package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
  43. package/plugins/beta/datasets/dist/umd/im-datasets-ml-adapter.js +1 -1
  44. package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +1 -1
  45. package/plugins/beta/datasets/dist/umd/index.js +1 -1
  46. package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.js +27 -9
  47. package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.test.js +46 -4
  48. package/plugins/beta/datasets/src/api/setFeatureVisibility.js +10 -1
  49. package/plugins/beta/datasets/src/api/setFeatureVisibility.test.js +48 -6
  50. package/plugins/beta/datasets/src/components/LayersMenu/Layers.module.scss +12 -12
  51. package/plugins/beta/datasets/src/reducers/datasetsToMenu.js +11 -6
  52. package/plugins/beta/datasets/src/reducers/datasetsToMenu.test.js +49 -0
  53. package/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.js +8 -1
  54. package/plugins/beta/datasets/src/reducers/pluginState.js +1 -1
  55. package/plugins/beta/datasets/src/registry/dataset.js +7 -3
  56. package/plugins/beta/datasets/src/registry/dataset.test.js +14 -0
  57. package/plugins/beta/datasets/src/registry/dynamicGeoJson.js +1 -1
  58. package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
  59. package/plugins/beta/draw-es/src/api/addFeature.js +12 -3
  60. package/plugins/beta/draw-es/src/events.js +8 -3
  61. package/plugins/beta/draw-es/src/events.test.js +2 -0
  62. package/plugins/beta/draw-es/src/graphic.js +26 -2
  63. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
  64. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
  65. package/plugins/beta/draw-ml/src/DrawInit.jsx +19 -0
  66. package/plugins/beta/draw-ml/src/api/newLine.js +1 -0
  67. package/plugins/beta/draw-ml/src/api/newPolygon.js +1 -0
  68. package/plugins/beta/draw-ml/src/modes/createDrawMode.js +52 -37
  69. package/plugins/beta/draw-ml/src/modes/editVertex/touchHandlers.js +1 -1
  70. package/plugins/beta/draw-ml/src/modes/editVertex/vertexOperations.js +5 -4
  71. package/plugins/beta/draw-ml/src/modes/editVertexMode.js +53 -21
  72. package/plugins/beta/draw-ol/dist/esm/DrawMode.js +1 -1
  73. package/plugins/beta/draw-ol/dist/esm/EditMode.js +1 -1
  74. package/plugins/beta/draw-ol/dist/esm/im-draw-ol-plugin.js +1 -1
  75. package/plugins/beta/draw-ol/src/core/OLDrawManager.js +3 -0
  76. package/plugins/beta/draw-ol/src/draw/DrawMode.js +57 -49
  77. package/plugins/beta/draw-ol/src/draw/drawInput.js +76 -32
  78. package/plugins/beta/draw-ol/src/edit/EditMode.js +4 -4
  79. package/plugins/beta/draw-ol/src/edit/keyboardHandler.js +4 -2
  80. package/plugins/beta/draw-ol/src/manifest.js +5 -1
  81. package/plugins/beta/draw-ol/src/reducer.js +1 -1
  82. package/plugins/beta/draw-ol/src/snap/snapEngine.js +75 -31
  83. package/plugins/beta/draw-ol/src/snap/snapGeometry.js +23 -46
  84. package/plugins/beta/draw-ol/src/snap/snapInteraction.js +30 -29
  85. package/plugins/beta/draw-ol/src/snap/snapManager.js +10 -1
  86. package/plugins/beta/draw-ol/src/utils/geometryHelpers.js +9 -3
  87. package/plugins/beta/draw-ol/src/utils/olCoords.js +2 -2
  88. package/plugins/beta/draw-ol/src/utils/spatial.js +4 -8
  89. package/plugins/beta/map-styles/src/mapStyles.scss +41 -41
  90. package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
  91. package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
  92. package/plugins/interact/dist/umd/index.js +1 -1
  93. package/plugins/interact/src/InteractInit.jsx +1 -3
  94. package/plugins/interact/src/InteractInit.test.js +0 -2
  95. package/plugins/interact/src/events.test.js +1 -1
  96. package/plugins/interact/src/hooks/useCrossHairVisibility.js +4 -10
  97. package/plugins/interact/src/hooks/useCrossHairVisibility.test.js +5 -10
  98. package/plugins/interact/src/hooks/useHighlightSync.js +1 -10
  99. package/plugins/interact/src/hooks/useHighlightSync.test.js +2 -21
  100. package/plugins/interact/src/hooks/useInteractionHandlers.js +5 -11
  101. package/plugins/interact/src/hooks/useInteractionHandlers.test.js +5 -25
  102. package/plugins/interact/src/reducer.js +4 -22
  103. package/plugins/interact/src/reducer.test.js +11 -39
  104. package/plugins/search/dist/css/index.css +5 -2
  105. package/plugins/search/src/components/Form/Form.module.scss +5 -2
  106. package/plugins/search/src/search.scss +4 -4
  107. package/providers/beta/openlayers/dist/esm/im-openlayers-provider.js +1 -1
  108. package/providers/beta/openlayers/dist/umd/im-openlayers-provider.js +1 -1
  109. package/providers/beta/openlayers/dist/umd/index.js +1 -1
  110. package/providers/beta/openlayers/src/utils/tileLayers.js +29 -2
  111. package/providers/beta/openlayers/src/utils/tileLayers.test.js +53 -1
  112. package/src/App/components/CrossHair/CrossHair.module.scss +8 -8
  113. package/src/App/components/MapButton/MapButton.jsx +14 -10
  114. package/src/App/components/MapButton/MapButton.module.scss +1 -1
  115. package/src/App/components/MapButton/MapButton.test.jsx +1 -1
  116. package/src/App/components/PopupMenu/PopupMenu.test.jsx +79 -0
  117. package/src/App/components/PopupMenu/usePopupMenu.js +61 -12
  118. package/src/App/hooks/useLayoutMeasurements.js +10 -2
  119. package/src/App/hooks/useResizeObserver.js +4 -2
  120. package/src/InteractiveMap/InteractiveMap.js +4 -4
  121. package/src/InteractiveMap/InteractiveMap.test.js +3 -3
  122. package/src/InteractiveMap/behaviourController.js +3 -1
  123. package/src/InteractiveMap/behaviourController.test.js +6 -3
  124. package/src/InteractiveMap/domStateManager.js +2 -0
  125. package/src/config/events.js +21 -3
  126. package/src/types.js +12 -3
  127. package/src/utils/findNextTabStop.js +3 -3
  128. package/src/utils/findNextTabStop.test.js +25 -1
  129. package/webpack.dev.mjs +1 -0
  130. package/docs/assets/images/screens-blue.jpg +0 -0
  131. package/docs/assets/images/screens-white.jpg +0 -0
@@ -7,7 +7,7 @@ import * as queryString from '../utils/queryString.js'
7
7
  import { updateDOMState } from './domStateManager.js'
8
8
 
9
9
  jest.mock('../utils/queryString.js')
10
- jest.mock('./domStateManager.js', () => ({ updateDOMState: jest.fn() }))
10
+ jest.mock('./domStateManager.js', () => ({ updateDOMState: jest.fn().mockReturnValue({ isFullscreen: false }) }))
11
11
 
12
12
  describe('shouldLoadComponent', () => {
13
13
  beforeEach(() => {
@@ -67,7 +67,8 @@ describe('setupBehavior', () => {
67
67
  loadApp: jest.fn(),
68
68
  removeApp: jest.fn(),
69
69
  hideApp: jest.fn(),
70
- showApp: jest.fn()
70
+ showApp: jest.fn(),
71
+ eventBus: { emit: jest.fn() }
71
72
  }
72
73
  // Default: viewport is wide
73
74
  window.matchMedia = jest.fn().mockImplementation(() => ({
@@ -187,14 +188,16 @@ describe('setupBehavior', () => {
187
188
  expect(mockMapInstance.showApp).not.toHaveBeenCalled()
188
189
  })
189
190
 
190
- it('calls updateDOMState when map is showing and should load', () => {
191
+ it('calls updateDOMState and emits APP_FULLSCREEN_CHANGE when map is showing and should load', () => {
191
192
  mockMapInstance._isHidden = false
192
193
  mockMapInstance._root = {} // has root
193
194
  queryString.getQueryParam.mockReturnValue(null)
195
+ updateDOMState.mockReturnValue({ isFullscreen: false })
194
196
 
195
197
  handleChange()
196
198
 
197
199
  expect(updateDOMState).toHaveBeenCalledWith(mockMapInstance)
200
+ expect(mockMapInstance.eventBus.emit).toHaveBeenCalledWith('app:fullscreenchange', { isFullscreen: false })
198
201
  expect(mockMapInstance.loadApp).not.toHaveBeenCalled()
199
202
  expect(mockMapInstance.showApp).not.toHaveBeenCalled()
200
203
  })
@@ -70,6 +70,8 @@ function updateDOMState (mapInstance, { isFullscreen: isFullscreenOverride } = {
70
70
  ? 'auto'
71
71
  : containerHeight
72
72
  rootEl.style.height = isFullscreen ? '100%' : height
73
+
74
+ return { isFullscreen }
73
75
  }
74
76
 
75
77
  /**
@@ -69,11 +69,13 @@ export const EVENTS = {
69
69
  * Fired after initial load (`loadApp`) and when the app is shown again after being hidden (`showApp`).
70
70
  * Subscribe to this event to react whenever the map becomes visible to the user.
71
71
  *
72
- * Payload: `{ statePreserved: boolean }` — `true` if the map state was preserved from a previous session.
72
+ * Payload:
73
+ * - `statePreserved: boolean` — `true` if the map state was preserved from a previous session.
74
+ * - `isFullscreen: boolean` — `true` if the map opened in fullscreen mode, `false` if inline.
73
75
  *
74
76
  * @example
75
- * map.on(EVENTS.APP_OPENED, ({ statePreserved }) => {
76
- * console.log('Map opened, state preserved:', statePreserved)
77
+ * map.on(EVENTS.APP_OPENED, ({ isFullscreen, statePreserved }) => {
78
+ * console.log('Map opened, fullscreen:', isFullscreen, 'state preserved:', statePreserved)
77
79
  * })
78
80
  */
79
81
  APP_OPENED: 'app:opened',
@@ -93,6 +95,22 @@ export const EVENTS = {
93
95
  */
94
96
  APP_CLOSED: 'app:closed',
95
97
 
98
+ /**
99
+ * Emitted when the map transitions between fullscreen and inline display while already visible.
100
+ *
101
+ * Fired during viewport resize in `hybrid` behaviour when the map crosses the fullscreen/inline
102
+ * threshold without being hidden and re-shown. Use this alongside `app:opened` and `app:closed`
103
+ * to track the map's display mode across all transitions.
104
+ *
105
+ * Payload: `{ isFullscreen: boolean }` — `true` if the map is now fullscreen, `false` if inline.
106
+ *
107
+ * @example
108
+ * map.on(EVENTS.APP_FULLSCREEN_CHANGE, ({ isFullscreen }) => {
109
+ * console.log('Display mode changed, fullscreen:', isFullscreen)
110
+ * })
111
+ */
112
+ APP_FULLSCREEN_CHANGE: 'app:fullscreenchange',
113
+
96
114
  /**
97
115
  * Emitted when a panel is opened.
98
116
  * Payload: { panelId: string }
package/src/types.js CHANGED
@@ -403,18 +403,27 @@
403
403
  * Falls back to `#0b0c0c` (light) or `#ffffff` (dark).
404
404
  * Injected as the `--map-overlay-foreground-color` CSS custom property.
405
405
  *
406
- * @property {'raster' | 'ogc-vt'} [type]
406
+ * @property {'vector' | 'raster' | 'wms' | 'ogc-vt'} [type]
407
407
  * Tile layer type. Controls how the map provider constructs the basemap source. Omit (or leave
408
408
  * undefined) for the default Mapbox GL vector tile path. The OpenLayers provider supports all
409
- * three types, enabling raster, standard vector tile, and OGC vector tile basemaps:
409
+ * four types, enabling raster, WMS, standard vector tile, and OGC vector tile basemaps:
410
410
  * - `'raster'` — XYZ raster tile source; `url` should be a tile URL template.
411
+ * - `'vector'` — Mapbox GL vector tile path; `url` should point to a Mapbox GL style document.
412
+ * - `'wms'` — WMS raster tile source; `url` should be the WMS service endpoint and `params`
413
+ * should provide the WMS request parameters.
414
+ * **Currently only supported by the OpenLayers provider.**
411
415
  * - `'ogc-vt'` — OGC API - Tiles vector tile source; `url` should point to an OGC style endpoint
412
416
  * that returns a Mapbox GL style document. **Currently only supported by the OpenLayers provider.**
413
417
  *
414
418
  * @property {string} url
415
419
  * URL for the style. For the default vector tile path and `'ogc-vt'`, this should be a URL that
416
420
  * returns a Mapbox GL style document (Mapbox Style Specification). For `'raster'`, this should
417
- * be an XYZ tile URL template with `{x}`, `{y}`, `{z}` placeholders.
421
+ * be an XYZ tile URL template with `{x}`, `{y}`, `{z}` placeholders. For `'wms'`, this should
422
+ * be the WMS service endpoint (the GetMap URL).
423
+ *
424
+ * @property {Object} [params]
425
+ * WMS request parameters. Passed directly to the OpenLayers `TileWMS` source when `type` is `'wms'`.
426
+ * Most WMS GetMap requests should include `LAYERS`. Example: `{ LAYERS: 'MyLayer', FORMAT: 'image/jpeg' }`.
418
427
  */
419
428
 
420
429
  /**
@@ -1,7 +1,7 @@
1
- export function findTabStop ({ el, direction }) {
2
- const focusableEls = document.querySelectorAll('input, button, select, textarea, a[href]')
1
+ export function findTabStop ({ el, direction, root = document }) {
2
+ const focusableEls = root.querySelectorAll('input, button, select, textarea, a[href]')
3
3
  const list = Array.prototype.filter.call(focusableEls, item => {
4
- return item.tabIndex >= 0
4
+ return item.tabIndex >= 0 && !!item.offsetParent
5
5
  })
6
6
  const index = list.indexOf(el)
7
7
  return list[direction === 'next' ? index + 1 : index - 1] || list[0]
@@ -7,9 +7,10 @@ import { findTabStop } from './findNextTabStop.js'
7
7
  // --- MOCK SETUP ---
8
8
  // Helper to create mock elements. The default value (tabIndex = 0)
9
9
  // is covered below by creating 'el1' without the second argument.
10
- const createMockElement = (id, tabIndex = 0) => ({
10
+ const createMockElement = (id, tabIndex = 0, offsetParent = {}) => ({
11
11
  id,
12
12
  tabIndex,
13
+ offsetParent,
13
14
  // Required so Jest knows which element is which in the array lookup
14
15
  toString: () => id
15
16
  })
@@ -74,4 +75,27 @@ describe('findTabStop', () => {
74
75
  // Assert: It wraps around to the first element, el1.
75
76
  expect(result).toBe(el1)
76
77
  })
78
+
79
+ // Test 4: Covers: skipping elements with no offsetParent (hidden, e.g. wrong-breakpoint duplicates).
80
+ it('should skip hidden elements (no offsetParent) even when tabIndex is valid', () => {
81
+ const el1 = createMockElement('el1', 0)
82
+ const hiddenEl = createMockElement('hidden', 0, null)
83
+ const el3 = createMockElement('el3', 0)
84
+
85
+ mockFocusableElements([el1, hiddenEl, el3])
86
+
87
+ const result = findTabStop({ el: el1, direction: 'next' })
88
+
89
+ expect(result).toBe(el3)
90
+ })
91
+
92
+ it('accepts a custom root to scope the search', () => {
93
+ const el1 = createMockElement('el1')
94
+ const scopedRoot = { querySelectorAll: jest.fn(() => [el1]) }
95
+
96
+ findTabStop({ el: el1, direction: 'next', root: scopedRoot })
97
+
98
+ expect(scopedRoot.querySelectorAll).toHaveBeenCalledTimes(1)
99
+ expect(document.querySelectorAll).not.toHaveBeenCalled()
100
+ })
77
101
  })
package/webpack.dev.mjs CHANGED
@@ -87,6 +87,7 @@ export default {
87
87
  NGD_BLACK_AND_WHITE_URL_27700: JSON.stringify(process.env.NGD_BLACK_AND_WHITE_URL_27700),
88
88
  // Aerial photography
89
89
  AERIAL_URL: JSON.stringify(process.env.AERIAL_URL),
90
+ APGB_WMS_URL: JSON.stringify(process.env.APGB_WMS_URL),
90
91
  // OS Maps API (27700 raster)
91
92
  MAPS_OUTDOOR_URL: JSON.stringify(process.env.MAPS_OUTDOOR_URL),
92
93
  MAPS_ROAD_URL: JSON.stringify(process.env.MAPS_ROAD_URL),
Binary file