@defra/interactive-map 0.0.30-alpha → 0.0.32-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 (247) 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/context.md +4 -4
  22. package/docs/api.md +166 -37
  23. package/docs/assets/css/docusaurus.scss +36 -4
  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/basic-map.jpg +0 -0
  27. package/docs/assets/images/button-first.jpg +0 -0
  28. package/docs/assets/images/deuteranopia-ozs-map-thumb.jpg +0 -0
  29. package/docs/assets/images/draw.jpg +0 -0
  30. package/docs/assets/images/marker-panel.jpg +0 -0
  31. package/docs/assets/images/night-ozs-map-thumb.jpg +0 -0
  32. package/docs/assets/images/outdoor-ozs-map-thumb.jpg +0 -0
  33. package/docs/assets/images/place-marker.jpg +0 -0
  34. package/docs/assets/images/screenshot.jpg +0 -0
  35. package/docs/assets/images/search.jpg +0 -0
  36. package/docs/assets/images/select-feature.jpg +0 -0
  37. package/docs/assets/images/style-switcher.jpg +0 -0
  38. package/docs/assets/images/toggle-marker-label.jpg +0 -0
  39. package/docs/assets/images/tritanopia-ozs-map-thumb.jpg +0 -0
  40. package/docs/examples/add-marker-with-panel.mdx +3 -3
  41. package/docs/examples/add-polygons.mdx +225 -0
  42. package/docs/examples/add-symbols.mdx +177 -0
  43. package/docs/examples/basic-map.mdx +2 -2
  44. package/docs/examples/draw-tools.mdx +271 -0
  45. package/docs/examples/index.mdx +95 -11
  46. package/docs/examples/place-marker.mdx +151 -0
  47. package/docs/examples/search-control.mdx +71 -0
  48. package/docs/examples/select-feature.mdx +146 -0
  49. package/docs/examples/style-switcher.mdx +135 -0
  50. package/docs/examples/toggle-marker-label.mdx +3 -3
  51. package/docs/plugins/datasets.md +157 -122
  52. package/docs/plugins/interact.md +1 -4
  53. package/docusaurus.config.cjs +9 -2
  54. package/govuk-prototype-kit.config.json +52 -2
  55. package/package.json +1 -1
  56. package/plugins/beta/datasets/dist/css/index.css +5 -2
  57. package/plugins/beta/datasets/dist/esm/im-datasets-ml-adapter.js +1 -0
  58. package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
  59. package/plugins/beta/datasets/dist/esm/index.js +1 -1
  60. package/plugins/beta/datasets/dist/umd/im-datasets-ml-adapter.js +2 -0
  61. package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +2 -0
  62. package/plugins/beta/datasets/dist/umd/index.js +2 -0
  63. package/plugins/beta/datasets/src/adapters/loadLayerAdapter.js +33 -0
  64. package/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.js +44 -120
  65. package/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js +145 -245
  66. package/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js +516 -0
  67. package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.js +209 -0
  68. package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.test.js +483 -0
  69. package/plugins/beta/datasets/src/api/addDataset.js +2 -5
  70. package/plugins/beta/datasets/src/api/addDataset.test.js +16 -0
  71. package/plugins/beta/datasets/src/api/getOpacity.js +14 -14
  72. package/plugins/beta/datasets/src/api/getOpacity.test.js +72 -0
  73. package/plugins/beta/datasets/src/api/getStyle.js +8 -9
  74. package/plugins/beta/datasets/src/api/getStyle.test.js +42 -0
  75. package/plugins/beta/datasets/src/api/removeDataset.js +7 -7
  76. package/plugins/beta/datasets/src/api/removeDataset.test.js +45 -0
  77. package/plugins/beta/datasets/src/api/setData.js +9 -3
  78. package/plugins/beta/datasets/src/api/setData.test.js +62 -0
  79. package/plugins/beta/datasets/src/api/setDatasetVisibility.js +5 -30
  80. package/plugins/beta/datasets/src/api/setDatasetVisibility.test.js +31 -0
  81. package/plugins/beta/datasets/src/api/setFeatureVisibility.js +9 -18
  82. package/plugins/beta/datasets/src/api/setFeatureVisibility.test.js +74 -0
  83. package/plugins/beta/datasets/src/api/setGlobals.js +20 -0
  84. package/plugins/beta/datasets/src/api/setGlobals.test.js +63 -0
  85. package/plugins/beta/datasets/src/api/setOpacity.js +8 -27
  86. package/plugins/beta/datasets/src/api/setOpacity.test.js +31 -0
  87. package/plugins/beta/datasets/src/api/setStyle.js +5 -21
  88. package/plugins/beta/datasets/src/api/setStyle.test.js +53 -0
  89. package/plugins/beta/datasets/src/components/Key/Key.jsx +51 -0
  90. package/plugins/beta/datasets/src/components/Key/KeyGroupItem.jsx +18 -0
  91. package/plugins/beta/datasets/src/components/Key/KeyItem.jsx +20 -0
  92. package/plugins/beta/datasets/src/components/Key/KeySvg.jsx +22 -0
  93. package/plugins/beta/datasets/src/components/Key/KeySvg.test.jsx +87 -0
  94. package/plugins/beta/datasets/src/components/Key/KeySvgLine.jsx +19 -0
  95. package/plugins/beta/datasets/src/components/Key/KeySvgLine.test.jsx +71 -0
  96. package/plugins/beta/datasets/src/components/{KeySvgPattern.jsx → Key/KeySvgPattern.jsx} +3 -4
  97. package/plugins/beta/datasets/src/components/Key/KeySvgPattern.test.jsx +55 -0
  98. package/plugins/beta/datasets/src/components/Key/KeySvgRect.jsx +22 -0
  99. package/plugins/beta/datasets/src/components/Key/KeySvgRect.test.jsx +85 -0
  100. package/plugins/beta/datasets/src/components/{KeySvgSymbol.jsx → Key/KeySvgSymbol.jsx} +5 -5
  101. package/plugins/beta/datasets/src/components/Key/KeySvgSymbol.test.jsx +80 -0
  102. package/plugins/beta/datasets/src/components/Key/svgProperties.test.js +61 -0
  103. package/plugins/beta/datasets/src/{panels → components/LayersMenu}/Layers.module.scss +15 -11
  104. package/plugins/beta/datasets/src/components/LayersMenu/LayersMenu.jsx +33 -0
  105. package/plugins/beta/datasets/src/components/LayersMenu/LayersMenuCheckbox.jsx +31 -0
  106. package/plugins/beta/datasets/src/components/LayersMenu/LayersMenuGroupWrapper.jsx +19 -0
  107. package/plugins/beta/datasets/src/datasets.scss +2 -2
  108. package/plugins/beta/datasets/src/fetch/createDynamicSource.js +8 -8
  109. package/plugins/beta/datasets/src/{DatasetsInit.jsx → initialise/DatasetsInit.jsx} +19 -21
  110. package/plugins/beta/datasets/src/{defaults.js → initialise/defaults.js} +17 -2
  111. package/plugins/beta/datasets/src/initialise/defaults.test.js +127 -0
  112. package/plugins/beta/datasets/src/{datasets.js → initialise/initialiseDatasets.js} +30 -26
  113. package/plugins/beta/datasets/src/initialise/initialiseDatasets.test.js +273 -0
  114. package/plugins/beta/datasets/src/manifest.js +8 -6
  115. package/plugins/beta/datasets/src/reducers/__data__/demoDatasets.js +253 -0
  116. package/plugins/beta/datasets/src/reducers/datasetsToMenu.js +83 -0
  117. package/plugins/beta/datasets/src/reducers/datasetsToMenu.test.js +84 -0
  118. package/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.js +41 -0
  119. package/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.test.js +117 -0
  120. package/plugins/beta/datasets/src/reducers/pluginState.js +206 -0
  121. package/plugins/beta/datasets/src/reducers/pluginState.test.js +386 -0
  122. package/plugins/beta/datasets/src/registry/__mocks__/datasetRegistry.js +29 -0
  123. package/plugins/beta/datasets/src/registry/createDataset.js +5 -0
  124. package/plugins/beta/datasets/src/registry/dataset.js +176 -0
  125. package/plugins/beta/datasets/src/registry/dataset.test.js +497 -0
  126. package/plugins/beta/datasets/src/registry/datasetDefinitionCache.js +35 -0
  127. package/plugins/beta/datasets/src/registry/datasetRegistry.js +116 -0
  128. package/plugins/beta/datasets/src/registry/datasetRegistry.test.js +335 -0
  129. package/plugins/beta/datasets/src/registry/dynamicGeoJson.js +17 -0
  130. package/plugins/beta/datasets/src/registry/globalDataset.js +36 -0
  131. package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
  132. package/plugins/beta/draw-es/src/api/addFeature.js +12 -3
  133. package/plugins/beta/draw-es/src/events.js +8 -3
  134. package/plugins/beta/draw-es/src/events.test.js +2 -0
  135. package/plugins/beta/draw-es/src/graphic.js +26 -2
  136. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
  137. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
  138. package/plugins/beta/draw-ml/src/DrawInit.jsx +8 -0
  139. package/plugins/beta/draw-ml/src/api/newLine.js +1 -0
  140. package/plugins/beta/draw-ml/src/api/newPolygon.js +1 -0
  141. package/plugins/beta/draw-ml/src/events.js +13 -1
  142. package/plugins/beta/draw-ml/src/index.js +1 -1
  143. package/plugins/beta/draw-ml/src/manifest.js +3 -0
  144. package/plugins/beta/draw-ml/src/modes/createDrawMode.js +21 -12
  145. package/plugins/beta/draw-ml/src/modes/editVertexMode.js +4 -0
  146. package/plugins/beta/draw-ol/dist/esm/EditMode.js +1 -1
  147. package/plugins/beta/draw-ol/dist/esm/im-draw-ol-plugin.js +1 -1
  148. package/plugins/beta/draw-ol/src/edit/keyboardHandler.js +4 -2
  149. package/plugins/beta/map-styles/src/mapStyles.scss +41 -41
  150. package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
  151. package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
  152. package/plugins/interact/dist/umd/index.js +1 -1
  153. package/plugins/interact/src/InteractInit.jsx +3 -5
  154. package/plugins/interact/src/InteractInit.test.js +1 -3
  155. package/plugins/interact/src/events.js +2 -29
  156. package/plugins/interact/src/events.test.js +4 -102
  157. package/plugins/interact/src/hooks/useAttachEvents.js +3 -4
  158. package/plugins/interact/src/hooks/useAttachEvents.test.js +1 -3
  159. package/plugins/interact/src/hooks/useCrossHairVisibility.js +4 -10
  160. package/plugins/interact/src/hooks/useCrossHairVisibility.test.js +5 -10
  161. package/plugins/interact/src/hooks/useHighlightSync.js +1 -10
  162. package/plugins/interact/src/hooks/useHighlightSync.test.js +2 -21
  163. package/plugins/interact/src/hooks/useInteractionHandlers.js +15 -12
  164. package/plugins/interact/src/hooks/useInteractionHandlers.test.js +28 -29
  165. package/plugins/interact/src/manifest.js +0 -35
  166. package/plugins/interact/src/manifest.test.js +3 -43
  167. package/plugins/interact/src/reducer.js +4 -22
  168. package/plugins/interact/src/reducer.test.js +11 -39
  169. package/plugins/search/dist/css/index.css +5 -2
  170. package/plugins/search/src/components/Form/Form.module.scss +5 -2
  171. package/plugins/search/src/search.scss +4 -4
  172. package/providers/beta/esri/dist/esm/im-esri-provider.js +1 -1
  173. package/providers/beta/esri/src/esriProvider.js +4 -0
  174. package/providers/beta/openlayers/dist/esm/im-openlayers-provider.js +1 -1
  175. package/providers/beta/openlayers/dist/umd/im-openlayers-provider.js +1 -1
  176. package/providers/beta/openlayers/src/openlayersProvider.js +4 -0
  177. package/providers/beta/openlayers/src/openlayersProvider.test.js +5 -0
  178. package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
  179. package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
  180. package/providers/maplibre/src/maplibreProvider.js +6 -4
  181. package/providers/maplibre/src/maplibreProvider.test.js +5 -0
  182. package/providers/maplibre/src/utils/highlightFeatures.js +74 -25
  183. package/providers/maplibre/src/utils/highlightFeatures.test.js +132 -0
  184. package/providers/maplibre/src/utils/patternImages.js +2 -4
  185. package/providers/maplibre/src/utils/symbolImages.js +1 -4
  186. package/rollup.esm.mjs +2 -8
  187. package/src/App/components/CrossHair/CrossHair.module.scss +8 -8
  188. package/src/App/components/MapButton/MapButton.jsx +16 -1
  189. package/src/App/components/MapButton/MapButton.module.scss +12 -1
  190. package/src/App/components/MapButton/MapButton.test.jsx +40 -1
  191. package/src/App/hooks/useContinueEnabledEvaluator.js +31 -0
  192. package/src/App/hooks/useContinueEnabledEvaluator.test.js +118 -0
  193. package/src/App/hooks/useEvaluateProp.js +15 -15
  194. package/src/App/hooks/useEvaluateProp.test.js +80 -76
  195. package/src/App/hooks/useLayoutMeasurements.js +11 -5
  196. package/src/App/hooks/useResizeObserver.js +15 -2
  197. package/src/App/hooks/useResizeObserver.test.js +1 -0
  198. package/src/App/renderer/PluginInits.jsx +2 -0
  199. package/src/App/renderer/mapButtons.js +21 -1
  200. package/src/App/renderer/mapButtons.test.js +46 -1
  201. package/src/App/store/appReducer.js +1 -1
  202. package/src/App/store/appReducer.test.js +37 -0
  203. package/src/InteractiveMap/InteractiveMap.js +14 -4
  204. package/src/InteractiveMap/InteractiveMap.test.js +11 -3
  205. package/src/InteractiveMap/behaviourController.js +3 -1
  206. package/src/InteractiveMap/behaviourController.test.js +6 -3
  207. package/src/InteractiveMap/domStateManager.js +2 -0
  208. package/src/config/appConfig.js +25 -0
  209. package/src/config/appConfig.test.js +50 -0
  210. package/src/config/defaults.js +1 -0
  211. package/src/config/events.js +21 -3
  212. package/src/scss/settings/_dimensions.scss +1 -0
  213. package/src/services/patternRegistry.js +8 -4
  214. package/src/types.js +7 -0
  215. package/src/utils/patternUtils.js +1 -2
  216. package/src/utils/patternUtils.test.js +9 -0
  217. package/webpack.dev.mjs +10 -0
  218. package/webpack.umd.mjs +1 -1
  219. package/docs/assets/images/screens-blue.jpg +0 -0
  220. package/docs/assets/images/screens-white.jpg +0 -0
  221. package/plugins/beta/datasets/dist/adapters/maplibre/esm/im-datasets-ml-adapter.js +0 -1
  222. package/plugins/beta/datasets/dist/adapters/maplibre/esm/index.js +0 -1
  223. package/plugins/beta/datasets/dist/umd/maplibre/im-datasets-maplibre-adapter.js +0 -2
  224. package/plugins/beta/datasets/dist/umd/maplibre/im-datasets-plugin.js +0 -2
  225. package/plugins/beta/datasets/dist/umd/maplibre/index.js +0 -2
  226. package/plugins/beta/datasets/src/adapters/maplibre/index.js +0 -18
  227. package/plugins/beta/datasets/src/adapters/maplibre/layerIds.js +0 -75
  228. package/plugins/beta/datasets/src/adapters/maplibre/patternImages.js +0 -27
  229. package/plugins/beta/datasets/src/adapters/maplibre/symbolImages.js +0 -31
  230. package/plugins/beta/datasets/src/components/KeySvg.jsx +0 -24
  231. package/plugins/beta/datasets/src/components/KeySvgLine.jsx +0 -19
  232. package/plugins/beta/datasets/src/components/KeySvgRect.jsx +0 -22
  233. package/plugins/beta/datasets/src/index.maplibre.umd.js +0 -23
  234. package/plugins/beta/datasets/src/panels/Key.jsx +0 -62
  235. package/plugins/beta/datasets/src/panels/Layers.jsx +0 -141
  236. package/plugins/beta/datasets/src/reducer.js +0 -219
  237. package/plugins/beta/datasets/src/reducers/keyReducer.js +0 -34
  238. package/plugins/beta/datasets/src/utils/filters.js +0 -34
  239. package/plugins/beta/datasets/src/utils/mergeSublayer.js +0 -86
  240. package/plugins/beta/draw-ml/dist/css/index.css +0 -21
  241. /package/plugins/beta/datasets/dist/umd/{maplibre/im-datasets-maplibre-adapter.js.LICENSE.txt → im-datasets-ml-adapter.js.LICENSE.txt} +0 -0
  242. /package/plugins/beta/datasets/dist/umd/{maplibre/im-datasets-plugin.js.LICENSE.txt → im-datasets-plugin.js.LICENSE.txt} +0 -0
  243. /package/plugins/beta/datasets/dist/umd/{maplibre/index.js.LICENSE.txt → index.js.LICENSE.txt} +0 -0
  244. /package/plugins/beta/datasets/src/components/{EmptyKey.jsx → Key/EmptyKey.jsx} +0 -0
  245. /package/plugins/beta/datasets/src/components/{EmptyKey.test.jsx → Key/EmptyKey.test.jsx} +0 -0
  246. /package/plugins/beta/datasets/src/{panels → components/Key}/Key.module.scss +0 -0
  247. /package/plugins/beta/datasets/src/components/{svgProperties.js → Key/svgProperties.js} +0 -0
@@ -2,11 +2,10 @@ import { attachEvents } from './events.js'
2
2
 
3
3
  const MOCK_POINT = { x: 1, y: 2 }
4
4
  const MOCK_COORDS = [1, 2]
5
- const INTERACT_DONE = 'interact:done'
6
5
 
7
6
  const createParams = () => {
8
7
  const appState = { layoutRefs: { viewportRef: { current: document.body } }, disabledButtons: new Set() }
9
- const pluginState = { dispatch: jest.fn(), selectionBounds: null, selectedFeatures: [], selectedMarkers: [], closeOnAction: true, multiSelect: false }
8
+ const pluginState = { dispatch: jest.fn(), selectedFeatures: [], selectedMarkers: [], multiSelect: false }
10
9
  const clickReadyRef = { current: false }
11
10
  return {
12
11
  appState,
@@ -18,11 +17,10 @@ const createParams = () => {
18
17
  markers: { remove: jest.fn(), getMarker: jest.fn(() => null) },
19
18
  crossHair: { getDetail: jest.fn(() => ({ point: { x: 0, y: 0 }, coords: [0, 0] })) }
20
19
  },
21
- buttonConfig: { selectDone: {}, selectAtTarget: {}, selectCancel: {} },
20
+ buttonConfig: { selectAtTarget: {} },
22
21
  events: { MAP_CLICK: 'map:click' },
23
22
  eventBus: { on: jest.fn(), off: jest.fn(), emit: jest.fn() },
24
- handleInteraction: jest.fn(),
25
- closeApp: jest.fn()
23
+ handleInteraction: jest.fn()
26
24
  }
27
25
  }
28
26
 
@@ -109,102 +107,6 @@ describe('attachEvents — click handling', () => {
109
107
  })
110
108
  })
111
109
 
112
- describe('attachEvents — button actions', () => {
113
- let cleanup = null
114
-
115
- beforeEach(() => { jest.useFakeTimers() })
116
- afterEach(() => { cleanup?.(); jest.useRealTimers() })
117
-
118
- it('selectDone emits correct payload and respects closeOnAction', () => {
119
- const params = createParams()
120
- cleanup = attachEvents(params)
121
-
122
- params.mapState.markers.getMarker.mockReturnValue({ coords: MOCK_COORDS })
123
- params.buttonConfig.selectDone.onClick()
124
- expect(params.closeApp).toHaveBeenCalled()
125
-
126
- params.closeApp.mockClear()
127
- params.pluginState.closeOnAction = false
128
- params.buttonConfig.selectDone.onClick()
129
- expect(params.closeApp).not.toHaveBeenCalled()
130
- })
131
-
132
- it('selectDone emits selectedFeatures and selectionBounds when no marker', () => {
133
- const params = createParams()
134
- cleanup = attachEvents(params)
135
-
136
- params.pluginState.selectedFeatures = [{ id: 'f1' }]
137
- params.pluginState.selectionBounds = { sw: [0, 0], ne: [1, 1] }
138
- params.buttonConfig.selectDone.onClick()
139
-
140
- expect(params.eventBus.emit).toHaveBeenCalledWith(INTERACT_DONE, {
141
- selectedFeatures: [{ id: 'f1' }],
142
- selectionBounds: { sw: [0, 0], ne: [1, 1] }
143
- })
144
- })
145
-
146
- it('selectDone includes selectedMarkers in payload when present', () => {
147
- const params = createParams()
148
- cleanup = attachEvents(params)
149
-
150
- params.pluginState.selectedMarkers = ['m1', 'm2']
151
- params.buttonConfig.selectDone.onClick()
152
-
153
- expect(params.eventBus.emit).toHaveBeenCalledWith(INTERACT_DONE,
154
- expect.objectContaining({ selectedMarkers: ['m1', 'm2'] })
155
- )
156
- })
157
-
158
- it('selectDone omits selectedMarkers from payload when empty', () => {
159
- const params = createParams()
160
- cleanup = attachEvents(params)
161
-
162
- params.buttonConfig.selectDone.onClick()
163
-
164
- const payload = params.eventBus.emit.mock.calls.find(c => c[0] === INTERACT_DONE)[1]
165
- expect(payload).not.toHaveProperty('selectedMarkers')
166
- })
167
-
168
- it('does not emit or closeApp if selectDone button is disabled', () => {
169
- const params = createParams()
170
- cleanup = attachEvents(params)
171
-
172
- params.appState.disabledButtons.add('selectDone')
173
- params.buttonConfig.selectDone.onClick()
174
-
175
- expect(params.eventBus.emit).not.toHaveBeenCalled()
176
- expect(params.closeApp).not.toHaveBeenCalled()
177
- })
178
-
179
- it('selectCancel emits cancel and respects closeOnAction', () => {
180
- const params = createParams()
181
- cleanup = attachEvents(params)
182
-
183
- params.buttonConfig.selectCancel.onClick()
184
- expect(params.closeApp).toHaveBeenCalled()
185
-
186
- cleanup()
187
- const params2 = createParams()
188
- cleanup = attachEvents(params2)
189
- params2.pluginState.closeOnAction = false
190
- params2.buttonConfig.selectCancel.onClick()
191
- expect(params2.closeApp).not.toHaveBeenCalled()
192
- })
193
-
194
- it('respects default closeOnAction when value is nullish', () => {
195
- const params = createParams()
196
- params.pluginState.closeOnAction = null
197
- cleanup = attachEvents(params)
198
-
199
- params.buttonConfig.selectDone.onClick()
200
- expect(params.closeApp).toHaveBeenCalledTimes(1)
201
-
202
- params.closeApp.mockClear()
203
- params.buttonConfig.selectCancel.onClick()
204
- expect(params.closeApp).toHaveBeenCalledTimes(1)
205
- })
206
- })
207
-
208
110
  describe('attachEvents — programmatic selection', () => {
209
111
  let cleanup = null
210
112
 
@@ -232,7 +134,7 @@ describe('attachEvents — cleanup', () => {
232
134
  const params = createParams()
233
135
  const cleanup = attachEvents(params)
234
136
  cleanup()
235
- Object.values(params.buttonConfig).forEach(btn => expect(btn.onClick).toBeNull())
137
+ expect(params.buttonConfig.selectAtTarget.onClick).toBeNull()
236
138
  jest.useRealTimers()
237
139
  })
238
140
  })
@@ -2,7 +2,7 @@ import { useEffect, useRef } from 'react'
2
2
  import { EVENTS } from '../../../../src/config/events.js'
3
3
  import { attachEvents } from '../events.js'
4
4
 
5
- export function useAttachEvents ({ pluginState, appState, mapState, buttonConfig, eventBus, handleInteraction, closeApp }) {
5
+ export function useAttachEvents ({ pluginState, appState, mapState, buttonConfig, eventBus, handleInteraction }) {
6
6
  // Refs updated synchronously each render — keeps callbacks fresh without re-attaching events
7
7
  const handleInteractionRef = useRef(handleInteraction)
8
8
  handleInteractionRef.current = handleInteraction
@@ -37,10 +37,9 @@ export function useAttachEvents ({ pluginState, appState, mapState, buttonConfig
37
37
  events: EVENTS,
38
38
  eventBus,
39
39
  handleInteraction: (event) => handleInteractionRef.current(event),
40
- clickReadyRef,
41
- closeApp
40
+ clickReadyRef
42
41
  })
43
42
 
44
43
  return cleanupEvents
45
- }, [pluginState.enabled, buttonConfig, eventBus, closeApp])
44
+ }, [pluginState.enabled, buttonConfig, eventBus])
46
45
  }
@@ -21,7 +21,6 @@ beforeEach(() => {
21
21
  mapState: { mapStyle: {} },
22
22
  buttonConfig: {},
23
23
  eventBus: { emit: jest.fn() },
24
- closeApp: jest.fn(),
25
24
  handleInteraction: handleInteractionMock
26
25
  }
27
26
  })
@@ -36,8 +35,7 @@ describe('useAttachEvents', () => {
36
35
  mapState: props.mapState,
37
36
  buttonConfig: props.buttonConfig,
38
37
  events: EVENTS,
39
- eventBus: props.eventBus,
40
- closeApp: props.closeApp
38
+ eventBus: props.eventBus
41
39
  }))
42
40
 
43
41
  const { getAppState, getPluginState, handleInteraction } = attachEvents.mock.calls.at(-1)[0]
@@ -1,5 +1,4 @@
1
1
  import { useCallback, useEffect, useRef } from 'react'
2
- import { getInterfaceType, subscribeToInterfaceChangesImmediate } from '../../../../src/utils/detectInterfaceType.js'
3
2
 
4
3
  export function useCrossHairVisibility ({ crossHair, enabled, selectMarkerOnly, appState }) {
5
4
  const enabledRef = useRef(enabled)
@@ -9,9 +8,11 @@ export function useCrossHairVisibility ({ crossHair, enabled, selectMarkerOnly,
9
8
  const crossHairRef = useRef(crossHair)
10
9
  crossHairRef.current = crossHair
11
10
  const listboxFocusRef = useRef(false)
11
+ const interfaceTypeRef = useRef(appState.interfaceType)
12
+ interfaceTypeRef.current = appState.interfaceType
12
13
 
13
14
  const updateCrossHair = useCallback(() => {
14
- const type = getInterfaceType()
15
+ const type = interfaceTypeRef.current
15
16
  const isToK = ['touch', 'keyboard'].includes(type)
16
17
  if (enabledRef.current && !listboxFocusRef.current && isToK && !(type === 'touch' && selectMarkerOnlyRef.current)) {
17
18
  crossHairRef.current.fixAtCenter()
@@ -20,17 +21,10 @@ export function useCrossHairVisibility ({ crossHair, enabled, selectMarkerOnly,
20
21
  }
21
22
  }, [])
22
23
 
23
- // Toggle target marker visibility on enabled/interactionModes changes
24
24
  useEffect(() => {
25
25
  updateCrossHair()
26
- }, [enabled, selectMarkerOnly, updateCrossHair])
26
+ }, [enabled, selectMarkerOnly, appState.interfaceType, updateCrossHair])
27
27
 
28
- // Toggle target marker visibility immediately on interface type change (no 150ms React delay)
29
- useEffect(() => {
30
- return subscribeToInterfaceChangesImmediate(updateCrossHair)
31
- }, [updateCrossHair])
32
-
33
- // Hide crosshair when listbox has focus
34
28
  useEffect(() => {
35
29
  const container = appState.layoutRefs?.appContainerRef?.current
36
30
  if (!container) { return undefined }
@@ -1,20 +1,15 @@
1
1
  import { act, renderHook } from '@testing-library/react'
2
2
  import { useCrossHairVisibility } from './useCrossHairVisibility.js'
3
- import { getInterfaceType } from '../../../../src/utils/detectInterfaceType.js'
4
-
5
- jest.mock('../../../../src/utils/detectInterfaceType.js', () => ({
6
- getInterfaceType: jest.fn(() => 'mouse'),
7
- subscribeToInterfaceChangesImmediate: jest.fn(() => () => {})
8
- }))
9
3
 
10
4
  let crossHair
11
5
  let appState
12
6
 
13
7
  beforeEach(() => {
14
- jest.clearAllMocks()
15
8
  crossHair = { fixAtCenter: jest.fn(), hide: jest.fn() }
16
- appState = { layoutRefs: { appContainerRef: { current: document.createElement('div') } } }
17
- getInterfaceType.mockReturnValue('mouse')
9
+ appState = {
10
+ interfaceType: 'mouse',
11
+ layoutRefs: { appContainerRef: { current: document.createElement('div') } }
12
+ }
18
13
  })
19
14
 
20
15
  describe('useCrossHairVisibility', () => {
@@ -26,7 +21,7 @@ describe('useCrossHairVisibility', () => {
26
21
 
27
22
  it('shows crosshair on touch/keyboard and hides when listbox has focus', () => {
28
23
  const container = appState.layoutRefs.appContainerRef.current
29
- getInterfaceType.mockReturnValue('touch')
24
+ appState.interfaceType = 'touch'
30
25
  renderHook(() => useCrossHairVisibility({ crossHair, enabled: true, selectMarkerOnly: false, appState }))
31
26
 
32
27
  expect(crossHair.fixAtCenter).toHaveBeenCalled()
@@ -9,16 +9,12 @@ import { buildStylesMap } from '../utils/buildStylesMap.js'
9
9
  * (shown with the keyboard cursor ring) as separate arguments so the provider can style them
10
10
  * differently. Also re-applies highlights after a map style reload, since highlight layers
11
11
  * are removed when the base style changes.
12
- *
13
- * Dispatches UPDATE_SELECTED_BOUNDS with the bounding box returned by the provider so
14
- * downstream consumers (e.g. interact:done) receive up-to-date bounds.
15
12
  */
16
13
  export const useHighlightSync = ({
17
14
  mapProvider,
18
15
  mapStyle,
19
16
  pluginState,
20
17
  selectedFeatures,
21
- dispatch,
22
18
  events,
23
19
  eventBus
24
20
  }) => {
@@ -37,12 +33,7 @@ export const useHighlightSync = ({
37
33
  const activeFeatures = listboxActiveItem
38
34
  ? [{ featureId: listboxActiveItem.featureId, layerId: listboxActiveItem.layerId, idProperty: listboxActiveItem.idProperty, geometry: listboxActiveItem.geometry }]
39
35
  : []
40
- const bounds = mapProvider.updateHighlightedFeatures?.(selectedFeatures, activeFeatures, stylesMap)
41
-
42
- dispatch({
43
- type: 'UPDATE_SELECTED_BOUNDS',
44
- payload: bounds
45
- })
36
+ mapProvider.updateHighlightedFeatures?.(selectedFeatures, activeFeatures, stylesMap)
46
37
  }
47
38
 
48
39
  useEffect(() => {
@@ -30,7 +30,6 @@ beforeEach(() => {
30
30
  layers: [{ layerId: 'layer1' }]
31
31
  },
32
32
  selectedFeatures: [],
33
- dispatch: jest.fn(),
34
33
  events: { MAP_STYLE_CHANGE: STYLE_CHANGE, MAP_DATA_CHANGE: DATA_CHANGE },
35
34
  eventBus: {
36
35
  on: jest.fn((event, handler) => {
@@ -51,7 +50,7 @@ beforeEach(() => {
51
50
  // ─── useHighlightSync — highlighting ─────────────────────────────────────────
52
51
 
53
52
  describe('useHighlightSync — highlighting', () => {
54
- it('updates map highlights and dispatches bounds', () => {
53
+ it('updates map highlights', () => {
55
54
  mockDeps.selectedFeatures = [{ featureId: 'F1', layerId: 'layer1' }]
56
55
 
57
56
  render()
@@ -61,22 +60,6 @@ describe('useHighlightSync — highlighting', () => {
61
60
  [],
62
61
  expect.any(Object)
63
62
  )
64
- expect(mockDeps.dispatch).toHaveBeenCalledWith({
65
- type: 'UPDATE_SELECTED_BOUNDS',
66
- payload: { sw: [0, 0], ne: [1, 1] }
67
- })
68
- })
69
-
70
- it('dispatches null bounds when provider returns null', () => {
71
- mockDeps.selectedFeatures = [{ featureId: 'F1' }]
72
- mockDeps.mapProvider.updateHighlightedFeatures.mockReturnValue(null)
73
-
74
- render()
75
-
76
- expect(mockDeps.dispatch).toHaveBeenCalledWith({
77
- type: 'UPDATE_SELECTED_BOUNDS',
78
- payload: null
79
- })
80
63
  })
81
64
  })
82
65
 
@@ -144,9 +127,7 @@ describe('useHighlightSync — guards', () => {
144
127
  mockDeps.mapProvider = null
145
128
  mockDeps.selectedFeatures = [{ featureId: 'F1' }]
146
129
 
147
- render()
148
-
149
- expect(mockDeps.dispatch).not.toHaveBeenCalled()
130
+ expect(() => render()).not.toThrow()
150
131
  })
151
132
 
152
133
  it('does nothing when mapStyle is null', () => {
@@ -37,15 +37,10 @@ const findMarkerAtPoint = (markers, point, scale) => {
37
37
  return null
38
38
  }
39
39
 
40
- const useSelectionChangeEmitter = (eventBus, selectedFeatures, selectedMarkers, selectionBounds) => {
40
+ const useSelectionChangeEmitter = (eventBus, selectedFeatures, selectedMarkers) => {
41
41
  const lastEmittedSelectionChange = useRef(null)
42
42
 
43
43
  useEffect(() => {
44
- const awaitingBounds = selectedFeatures.length > 0 && !selectionBounds
45
- if (awaitingBounds) {
46
- return
47
- }
48
-
49
44
  const prev = lastEmittedSelectionChange.current
50
45
  const wasEmpty = prev === null || (prev.features.length === 0 && prev.markers.length === 0)
51
46
  if (wasEmpty && selectedFeatures.length === 0 && selectedMarkers.length === 0) {
@@ -53,14 +48,13 @@ const useSelectionChangeEmitter = (eventBus, selectedFeatures, selectedMarkers,
53
48
  }
54
49
 
55
50
  eventBus.emit('interact:selectionchange', {
56
- selectedFeatures,
51
+ selectedFeatures: selectedFeatures.map(({ featureId, layerId, idProperty, properties }) => ({ featureId, layerId, idProperty, properties })),
57
52
  selectedMarkers,
58
- selectionBounds,
59
53
  contiguous: areAllContiguous(selectedFeatures)
60
54
  })
61
55
 
62
56
  lastEmittedSelectionChange.current = { features: selectedFeatures, markers: selectedMarkers }
63
- }, [selectedFeatures, selectedMarkers, selectionBounds])
57
+ }, [selectedFeatures, selectedMarkers])
64
58
  }
65
59
 
66
60
  /**
@@ -166,6 +160,15 @@ const resolveContiguousDispatch = ({ featureId, feature, config, selectedFeature
166
160
  return true
167
161
  }
168
162
 
163
+ const logDebugFeatures = (coords, features) => {
164
+ const [lng, lat] = coords
165
+ console.groupCollapsed(`[interact] click (${lng.toFixed(4)}, ${lat.toFixed(4)}) — ${features.length} feature${features.length !== 1 ? 's' : ''}`) // NOSONAR
166
+ features.forEach(f => { // NOSONAR
167
+ console.log({ layer: f.layer.id, type: f.layer.type, id: f.id ?? '—', sourceLayer: f.sourceLayer ?? '—', properties: f.properties }) // NOSONAR
168
+ })
169
+ console.groupEnd() // NOSONAR
170
+ }
171
+
169
172
  /**
170
173
  * Core interaction hook. Processes map clicks in fixed priority order:
171
174
  * selectMarker → selectFeature → placeMarker (fallback).
@@ -185,7 +188,7 @@ const useHandleInteraction = ({ mapProvider, layers, interactionModes, multiSele
185
188
  return useCallback(({ point, coords }) => {
186
189
  const debugFeatures = debug ? getFeaturesAtPoint(mapProvider, point, { radius: tolerance }) : null
187
190
  if (debugFeatures) {
188
- console.log(`--- Features at ${coords} ---`, debugFeatures) // NOSONAR
191
+ logDebugFeatures(coords, debugFeatures)
189
192
  }
190
193
  if (interactionModes.includes('selectMarker')) {
191
194
  const markerHit = findMarkerAtPoint(markers, point, scale)
@@ -211,7 +214,7 @@ export const useInteractionHandlers = ({ mapState, pluginState, services, mapPro
211
214
  const {
212
215
  dispatch, layers, interactionModes, multiSelect, contiguous,
213
216
  marker: markerOptions, tolerance, selectedFeatures, selectedMarkers,
214
- selectionBounds, deselectOnClickOutside
217
+ deselectOnClickOutside
215
218
  } = pluginState
216
219
  const { eventBus } = services
217
220
  const layerConfigMap = buildLayerConfigMap(layers)
@@ -263,6 +266,6 @@ export const useInteractionHandlers = ({ mapState, pluginState, services, mapPro
263
266
  scale
264
267
  })
265
268
 
266
- useSelectionChangeEmitter(eventBus, selectedFeatures, selectedMarkers, selectionBounds)
269
+ useSelectionChangeEmitter(eventBus, selectedFeatures, selectedMarkers)
267
270
  return { handleInteraction }
268
271
  }
@@ -65,7 +65,6 @@ const setup = (pluginOverrides = {}, markerItems = [], markerRefs = new Map()) =
65
65
  marker: { symbol: 'pin', backgroundColor: 'red' },
66
66
  selectedFeatures: [],
67
67
  selectedMarkers: [],
68
- selectionBounds: null,
69
68
  ...pluginOverrides
70
69
  },
71
70
  services: {
@@ -345,30 +344,12 @@ it('does not check markers when selectMarker is not in interactionModes', () =>
345
344
  /* Selection change event */
346
345
  /* ------------------------------------------------------------------ */
347
346
 
348
- it('does not emit selectionchange when features are selected but bounds not yet calculated', () => {
347
+ it('emits selectionchange when features are selected', () => {
349
348
  const deps = {
350
349
  mapState: { markers: { add: jest.fn(), remove: jest.fn(), items: [], markerRefs: new Map() } },
351
350
  pluginState: {
352
- selectedFeatures: [{ featureId: 'F1' }],
353
- selectedMarkers: [],
354
- selectionBounds: null
355
- },
356
- services: { eventBus: { emit: jest.fn() } },
357
- mapProvider: { getFeatureGeometry: jest.fn(() => null) }
358
- }
359
-
360
- renderHook(() => useInteractionHandlers(deps))
361
-
362
- expect(deps.services.eventBus.emit).not.toHaveBeenCalled()
363
- })
364
-
365
- it('emits selectionchange once when bounds exist', () => {
366
- const deps = {
367
- mapState: { markers: { add: jest.fn(), remove: jest.fn(), items: [], markerRefs: new Map() } },
368
- pluginState: {
369
- selectedFeatures: [{ featureId: 'F1' }],
370
- selectedMarkers: [],
371
- selectionBounds: { sw: [0, 0], ne: [1, 1] }
351
+ selectedFeatures: [{ featureId: 'F1', layerId: 'l1', idProperty: 'id', properties: { name: 'A' }, geometry: { type: 'Point', coordinates: [0, 0] } }],
352
+ selectedMarkers: []
372
353
  },
373
354
  services: { eventBus: { emit: jest.fn() } },
374
355
  mapProvider: { getFeatureGeometry: jest.fn(() => null) }
@@ -379,9 +360,8 @@ it('emits selectionchange once when bounds exist', () => {
379
360
  expect(deps.services.eventBus.emit).toHaveBeenCalledWith(
380
361
  'interact:selectionchange',
381
362
  expect.objectContaining({
382
- selectedFeatures: deps.pluginState.selectedFeatures,
363
+ selectedFeatures: [{ featureId: 'F1', layerId: 'l1', idProperty: 'id', properties: { name: 'A' } }],
383
364
  selectedMarkers: [],
384
- selectionBounds: deps.pluginState.selectionBounds,
385
365
  contiguous: false
386
366
  })
387
367
  )
@@ -394,7 +374,7 @@ it('skips emission when selection remains empty after being cleared', () => {
394
374
  const { rerender } = renderHook(
395
375
  ({ features }) => useInteractionHandlers({
396
376
  mapState: { markers: { items: [], markerRefs: new Map() } },
397
- pluginState: { selectedFeatures: features, selectedMarkers: [], selectionBounds: { b: 1 } },
377
+ pluginState: { selectedFeatures: features, selectedMarkers: [] },
398
378
  services: { eventBus },
399
379
  mapProvider: { getFeatureGeometry: jest.fn(() => null) }
400
380
  }),
@@ -423,18 +403,37 @@ it('skips emission when selection remains empty after being cleared', () => {
423
403
  /* ------------------------------------------------------------------ */
424
404
 
425
405
  it('logs features when debug mode is enabled', () => {
406
+ const groupSpy = jest.spyOn(console, 'groupCollapsed').mockImplementation(() => {})
426
407
  const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {})
408
+ const groupEndSpy = jest.spyOn(console, 'groupEnd').mockImplementation(() => {})
427
409
 
428
410
  const { result } = setup({ debug: true })
429
411
 
430
412
  click(result)
431
413
 
432
- expect(logSpy).toHaveBeenCalledWith(
433
- expect.stringContaining('--- Features at'),
434
- expect.any(Array)
435
- )
414
+ expect(groupSpy).toHaveBeenCalledWith(expect.stringContaining('[interact] click ('))
415
+ expect(groupSpy).toHaveBeenCalledWith(expect.stringContaining('1 feature'))
416
+ expect(logSpy).toHaveBeenCalledWith(expect.objectContaining({ layer: 'parcels' }))
417
+ expect(groupEndSpy).toHaveBeenCalled()
436
418
 
419
+ groupSpy.mockRestore()
437
420
  logSpy.mockRestore()
421
+ groupEndSpy.mockRestore()
422
+ })
423
+
424
+ it('uses plural label when multiple features are found', () => {
425
+ const groupSpy = jest.spyOn(console, 'groupCollapsed').mockImplementation(() => {})
426
+ jest.spyOn(console, 'log').mockImplementation(() => {})
427
+ jest.spyOn(console, 'groupEnd').mockImplementation(() => {})
428
+
429
+ featureQueries.getFeaturesAtPoint.mockReturnValue([baseFeature, baseFeature])
430
+
431
+ const { result } = setup({ debug: true })
432
+ click(result)
433
+
434
+ expect(groupSpy).toHaveBeenCalledWith(expect.stringContaining('2 features'))
435
+
436
+ jest.restoreAllMocks()
438
437
  })
439
438
 
440
439
  /* ------------------------------------------------------------------ */
@@ -21,23 +21,6 @@ export const manifest = {
21
21
  },
22
22
 
23
23
  buttons: [{
24
- id: 'selectCancel',
25
- label: 'Back',
26
- variant: 'tertiary',
27
- hiddenWhen: ({ appConfig, appState, pluginState }) => !pluginState.enabled || !(['hybrid', 'buttonFirst'].includes(appConfig.behaviour) && appState.isFullscreen),
28
- mobile: {
29
- slot: 'actions',
30
- showLabel: true
31
- },
32
- tablet: {
33
- slot: 'actions',
34
- showLabel: true
35
- },
36
- desktop: {
37
- slot: 'actions',
38
- showLabel: true
39
- }
40
- }, {
41
24
  id: 'selectAtTarget',
42
25
  label: 'Select',
43
26
  variant: 'primary',
@@ -54,24 +37,6 @@ export const manifest = {
54
37
  desktop: {
55
38
  slot: 'actions'
56
39
  }
57
- }, {
58
- id: 'selectDone',
59
- label: 'Continue',
60
- variant: 'primary',
61
- excludeWhen: ({ appState, pluginState }) => !pluginState.enabled || !appState.isFullscreen,
62
- enableWhen: ({ mapState, pluginState }) => !!mapState.markers.items.some(m => m.id === 'location') || !!pluginState.selectionBounds,
63
- mobile: {
64
- slot: 'actions',
65
- showLabel: true
66
- },
67
- tablet: {
68
- slot: 'actions',
69
- showLabel: true
70
- },
71
- desktop: {
72
- slot: 'actions',
73
- showLabel: true
74
- }
75
40
  }],
76
41
 
77
42
  keyboardShortcuts: [
@@ -18,7 +18,9 @@ describe('manifest', () => {
18
18
 
19
19
  it('defines buttons with correct ids', () => {
20
20
  const ids = manifest.buttons.map(b => b.id)
21
- expect(ids).toEqual(expect.arrayContaining(['selectDone', 'selectAtTarget', 'selectCancel']))
21
+ expect(ids).toEqual(expect.arrayContaining(['selectAtTarget']))
22
+ expect(ids).not.toContain('selectDone')
23
+ expect(ids).not.toContain('selectCancel')
22
24
  })
23
25
 
24
26
  it('buttons have slots and showLabel', () => {
@@ -33,54 +35,12 @@ describe('manifest', () => {
33
35
  })
34
36
 
35
37
  it('button logic functions cover all branches', () => {
36
- const done = manifest.buttons.find(b => b.id === 'selectDone')
37
38
  const atTarget = manifest.buttons.find(b => b.id === 'selectAtTarget')
38
- const cancel = manifest.buttons.find(b => b.id === 'selectCancel')
39
-
40
- // selectDone.excludeWhen
41
- expect(done.excludeWhen({ appState: { isFullscreen: false }, pluginState: { enabled: true } })).toBe(true)
42
- expect(done.excludeWhen({ appState: { isFullscreen: true }, pluginState: { enabled: true } })).toBe(false)
43
-
44
- // selectDone.enableWhen
45
- expect(done.enableWhen({
46
- mapState: { markers: { items: [{ id: 'location' }] } },
47
- pluginState: { selectionBounds: null }
48
- })).toBe(true)
49
- expect(done.enableWhen({
50
- mapState: { markers: { items: [] } },
51
- pluginState: { selectionBounds: null }
52
- })).toBe(false)
53
- expect(done.enableWhen({
54
- mapState: { markers: { items: [] } },
55
- pluginState: { selectionBounds: { sw: [0, 0], ne: [1, 1] } }
56
- })).toBe(true)
57
39
 
58
40
  // selectAtTarget.hiddenWhen
59
41
  expect(atTarget.hiddenWhen({ appState: { interfaceType: 'pointer' }, pluginState: { enabled: true } })).toBe(true)
60
42
  expect(atTarget.hiddenWhen({ appState: { interfaceType: 'touch' }, pluginState: { enabled: true } })).toBe(false)
61
43
  expect(atTarget.hiddenWhen({ appState: { interfaceType: 'touch' }, pluginState: { enabled: false } })).toBe(true)
62
-
63
- // selectCancel.hiddenWhen
64
- expect(cancel.hiddenWhen({
65
- appConfig: { behaviour: 'always' },
66
- appState: { isFullscreen: true },
67
- pluginState: { enabled: true }
68
- })).toBe(true)
69
- expect(cancel.hiddenWhen({
70
- appConfig: { behaviour: 'hybrid' },
71
- appState: { isFullscreen: true },
72
- pluginState: { enabled: true }
73
- })).toBe(false)
74
- expect(cancel.hiddenWhen({
75
- appConfig: { behaviour: 'hybrid' },
76
- appState: { isFullscreen: false },
77
- pluginState: { enabled: true }
78
- })).toBe(true)
79
- expect(cancel.hiddenWhen({
80
- appConfig: { behaviour: 'hybrid' },
81
- appState: { isFullscreen: true },
82
- pluginState: { enabled: false }
83
- })).toBe(true)
84
44
  })
85
45
 
86
46
  it('keyboardShortcuts array exists', () => {