@defra/interactive-map 0.0.21-alpha → 0.0.23-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 (218) hide show
  1. package/dist/css/index.css +1 -1
  2. package/dist/esm/im-core.js +1 -1
  3. package/dist/esm/im-shell.js +1 -1
  4. package/dist/esm/index.js +1 -1
  5. package/dist/umd/im-core.js +1 -1
  6. package/dist/umd/index.js +1 -1
  7. package/docs/api/button-definition.md +39 -0
  8. package/docs/api/context.md +4 -4
  9. package/docs/api/map-style-config.md +11 -2
  10. package/docs/api/marker-config.md +38 -7
  11. package/docs/api/panel-definition.md +7 -3
  12. package/docs/api/symbol-config.md +10 -26
  13. package/docs/api/symbol-registry.md +28 -13
  14. package/docs/api.md +65 -4
  15. package/docs/assets/css/{docusaurus.css → docusaurus.scss} +18 -12
  16. package/docs/assets/images/toggle-marker-label.jpg +0 -0
  17. package/docs/examples/index.mdx +12 -0
  18. package/docs/examples/toggle-marker-label.mdx +89 -0
  19. package/docs/plugins/datasets.md +39 -1
  20. package/docs/plugins/interact.md +4 -11
  21. package/docusaurus.config.cjs +2 -1
  22. package/package.json +10 -12
  23. package/plugins/beta/datasets/dist/adapters/maplibre/esm/im-datasets-ml-adapter.js +1 -0
  24. package/plugins/beta/datasets/dist/css/index.css +2 -2
  25. package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
  26. package/plugins/beta/datasets/dist/umd/maplibre/im-datasets-maplibre-adapter.js +2 -0
  27. package/plugins/beta/datasets/dist/umd/maplibre/im-datasets-plugin.js +2 -0
  28. package/plugins/beta/datasets/dist/umd/maplibre/index.js +2 -0
  29. package/plugins/beta/datasets/src/adapters/maplibre/index.js +1 -1
  30. package/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.js +5 -5
  31. package/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js +24 -29
  32. package/plugins/beta/datasets/src/adapters/maplibre/patternImages.js +2 -2
  33. package/plugins/beta/datasets/src/adapters/maplibre/symbolImages.js +3 -3
  34. package/plugins/beta/datasets/src/components/KeySvg.jsx +2 -2
  35. package/plugins/beta/datasets/src/components/KeySvgPattern.jsx +1 -2
  36. package/plugins/beta/datasets/src/components/svgProperties.js +2 -2
  37. package/plugins/beta/datasets/src/index.maplibre.umd.js +23 -0
  38. package/plugins/beta/datasets/src/panels/Key.module.scss +2 -2
  39. package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
  40. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
  41. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
  42. package/plugins/beta/map-styles/dist/esm/im-map-styles-plugin.js +1 -1
  43. package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -1
  44. package/plugins/beta/map-styles/dist/umd/index.js +1 -1
  45. package/plugins/beta/use-location/dist/esm/im-use-location-plugin.js +1 -1
  46. package/plugins/beta/use-location/dist/umd/im-use-location-plugin.js +1 -1
  47. package/plugins/beta/use-location/src/manifest.js +1 -0
  48. package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
  49. package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
  50. package/plugins/interact/dist/umd/index.js +1 -1
  51. package/plugins/interact/src/InteractInit.jsx +23 -55
  52. package/plugins/interact/src/InteractInit.test.js +58 -80
  53. package/plugins/interact/src/defaults.js +1 -3
  54. package/plugins/interact/src/hooks/useAttachEvents.js +46 -0
  55. package/plugins/interact/src/hooks/useAttachEvents.test.js +65 -0
  56. package/plugins/interact/src/hooks/useCrossHairVisibility.js +47 -0
  57. package/plugins/interact/src/hooks/useCrossHairVisibility.test.js +54 -0
  58. package/plugins/interact/src/hooks/useHighlightSync.js +30 -8
  59. package/plugins/interact/src/hooks/useHighlightSync.test.js +127 -80
  60. package/plugins/interact/src/hooks/useInteractionHandlers.js +18 -17
  61. package/plugins/interact/src/hooks/useInteractionHandlers.test.js +22 -61
  62. package/plugins/interact/src/hooks/useMapItemList.js +187 -0
  63. package/plugins/interact/src/hooks/useMapItemList.test.js +584 -0
  64. package/plugins/interact/src/index.js +0 -2
  65. package/plugins/interact/src/index.test.js +0 -2
  66. package/plugins/interact/src/manifest.js +37 -6
  67. package/plugins/interact/src/reducer.js +8 -4
  68. package/plugins/interact/src/reducer.test.js +18 -3
  69. package/plugins/interact/src/utils/buildStylesMap.js +21 -10
  70. package/plugins/interact/src/utils/buildStylesMap.test.js +29 -29
  71. package/plugins/interact/src/utils/spatial.js +0 -15
  72. package/plugins/interact/src/utils/spatial.test.js +1 -13
  73. package/plugins/search/dist/css/index.css +1 -1
  74. package/plugins/search/dist/esm/im-search-plugin.js +1 -1
  75. package/plugins/search/dist/umd/im-search-plugin.js +1 -1
  76. package/plugins/search/src/components/CloseButton/CloseButton.module.scss +2 -0
  77. package/plugins/search/src/components/OpenButton/OpenButton.jsx +1 -1
  78. package/plugins/search/src/components/OpenButton/OpenButton.module.scss +3 -0
  79. package/plugins/search/src/search.scss +1 -0
  80. package/providers/beta/esri/dist/esm/im-esri-provider.js +1 -1
  81. package/providers/beta/esri/src/esriProvider.js +4 -0
  82. package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
  83. package/providers/maplibre/dist/esm/index.js +1 -1
  84. package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
  85. package/providers/maplibre/dist/umd/index.js +1 -1
  86. package/providers/maplibre/src/index.js +7 -1
  87. package/providers/maplibre/src/index.test.js +15 -2
  88. package/providers/maplibre/src/mapEvents.js +11 -5
  89. package/providers/maplibre/src/mapEvents.test.js +14 -3
  90. package/providers/maplibre/src/maplibreProvider.js +18 -11
  91. package/providers/maplibre/src/maplibreProvider.test.js +43 -36
  92. package/providers/maplibre/src/utils/highlightFeatures.js +102 -57
  93. package/providers/maplibre/src/utils/highlightFeatures.test.js +162 -51
  94. package/providers/maplibre/src/utils/maplibreFixes.js +10 -0
  95. package/providers/maplibre/src/utils/maplibreFixes.test.js +31 -0
  96. package/providers/maplibre/src/utils/patternImages.js +10 -12
  97. package/providers/maplibre/src/utils/patternImages.test.js +145 -167
  98. package/providers/maplibre/src/utils/rasteriseToImageData.js +1 -4
  99. package/providers/maplibre/src/utils/rasteriseToImageData.test.js +23 -24
  100. package/providers/maplibre/src/utils/symbolImages.js +23 -86
  101. package/providers/maplibre/src/utils/symbolImages.test.js +60 -105
  102. package/rollup.esm.mjs +1 -1
  103. package/src/App/components/Actions/Actions.module.scss +1 -0
  104. package/src/App/components/Actions/Actions.test.jsx +17 -4
  105. package/src/App/components/Hints/Hints.jsx +52 -0
  106. package/src/App/components/Hints/Hints.module.scss +37 -0
  107. package/src/App/components/Hints/Hints.test.jsx +104 -0
  108. package/src/App/components/KeyboardHelp/KeyboardHelp.jsx +57 -19
  109. package/src/App/components/KeyboardHelp/KeyboardHelp.module.scss +10 -0
  110. package/src/App/components/KeyboardHelp/KeyboardHelp.test.jsx +140 -31
  111. package/src/App/components/Markers/LabelMarker.jsx +14 -0
  112. package/src/App/components/Markers/LabelMarker.test.jsx +36 -0
  113. package/src/App/components/Markers/Markers.jsx +44 -75
  114. package/src/App/components/Markers/Markers.module.scss +58 -0
  115. package/src/App/components/Markers/Markers.test.jsx +90 -113
  116. package/src/App/components/Markers/SymbolLabelMarker.jsx +43 -0
  117. package/src/App/components/Markers/SymbolLabelMarker.test.jsx +56 -0
  118. package/src/App/components/Markers/SymbolMarker.jsx +31 -0
  119. package/src/App/components/Markers/SymbolMarker.test.jsx +72 -0
  120. package/src/App/components/Panel/Panel.jsx +1 -1
  121. package/src/App/components/Panel/Panel.module.scss +1 -0
  122. package/src/App/components/PopupMenu/PopupMenu.test.jsx +117 -1
  123. package/src/App/components/PopupMenu/usePopupMenu.js +132 -85
  124. package/src/App/components/Tabs/Tabs.jsx +68 -0
  125. package/src/App/components/Tabs/Tabs.module.scss +57 -0
  126. package/src/App/components/Tabs/Tabs.test.jsx +121 -0
  127. package/src/App/components/Tooltip/Tooltip.module.scss +1 -1
  128. package/src/App/components/Viewport/Features.jsx +35 -0
  129. package/src/App/components/Viewport/Features.module.scss +31 -0
  130. package/src/App/components/Viewport/Features.test.jsx +124 -0
  131. package/src/App/components/Viewport/MapController.jsx +1 -1
  132. package/src/App/components/Viewport/MapStatus.jsx +0 -4
  133. package/src/App/components/Viewport/Viewport.jsx +35 -29
  134. package/src/App/components/Viewport/Viewport.module.scss +7 -21
  135. package/src/App/components/Viewport/Viewport.test.jsx +108 -65
  136. package/src/App/controls/keyboardActions.js +9 -3
  137. package/src/App/controls/keyboardActions.test.js +122 -87
  138. package/src/App/controls/keyboardShortcuts.js +1 -14
  139. package/src/App/hooks/useFeatureFocus.js +199 -0
  140. package/src/App/hooks/useFeatureFocus.test.js +635 -0
  141. package/src/App/hooks/useFeatureItems.js +30 -0
  142. package/src/App/hooks/useFeatureItems.test.js +97 -0
  143. package/src/App/hooks/useFocusVisible.js +4 -7
  144. package/src/App/hooks/useFocusVisible.test.js +6 -6
  145. package/src/App/hooks/useKeyboardHint.js +9 -34
  146. package/src/App/hooks/useKeyboardHint.test.js +34 -84
  147. package/src/App/hooks/useKeyboardShortcuts.js +8 -5
  148. package/src/App/hooks/useKeyboardShortcuts.test.js +16 -12
  149. package/src/App/hooks/useLayoutMeasurements.js +10 -4
  150. package/src/App/hooks/useLayoutMeasurements.test.js +30 -0
  151. package/src/App/hooks/useMapURLSync.js +3 -3
  152. package/src/App/hooks/useMapURLSync.test.js +20 -3
  153. package/src/App/hooks/useMarkerCursor.js +33 -0
  154. package/src/App/hooks/useMarkerCursor.test.js +87 -0
  155. package/src/App/hooks/useMarkersAPI.js +32 -9
  156. package/src/App/hooks/useMarkersAPI.test.js +162 -94
  157. package/src/App/layout/Layout.jsx +2 -0
  158. package/src/App/layout/Layout.test.jsx +3 -0
  159. package/src/App/registry/keyboardShortcutRegistry.js +3 -2
  160. package/src/App/registry/keyboardShortcutRegistry.test.js +6 -8
  161. package/src/App/renderer/mapButtons.js +5 -1
  162. package/src/App/renderer/mapButtons.test.js +37 -1
  163. package/src/App/store/ServiceProvider.jsx +4 -1
  164. package/src/App/store/ServiceProvider.test.jsx +11 -0
  165. package/src/App/store/appActionsMap.js +5 -1
  166. package/src/App/store/appActionsMap.test.js +13 -0
  167. package/src/App/store/appReducer.js +1 -0
  168. package/src/App/store/mapActionsMap.js +2 -1
  169. package/src/InteractiveMap/InteractiveMap.js +13 -1
  170. package/src/InteractiveMap/InteractiveMap.test.js +6 -4
  171. package/src/InteractiveMap/behaviourController.js +1 -2
  172. package/src/InteractiveMap/buttonManager.js +1 -3
  173. package/src/InteractiveMap/buttonManager.test.js +16 -8
  174. package/src/InteractiveMap/domStateManager.js +2 -3
  175. package/src/InteractiveMap/historyManager.js +4 -3
  176. package/src/config/appConfig.js +3 -1
  177. package/src/config/appConfig.test.js +4 -0
  178. package/src/config/defaults.js +3 -2
  179. package/src/config/events.js +8 -0
  180. package/src/config/mapTheme.js +8 -4
  181. package/src/config/mergeConfig.js +8 -2
  182. package/src/config/mergeConfig.test.js +19 -0
  183. package/src/config/symbolConfig.js +23 -16
  184. package/src/scss/main.scss +3 -0
  185. package/src/scss/tools/_border-focus.scss +0 -1
  186. package/src/services/eventBus.js +15 -0
  187. package/src/services/eventBus.test.js +11 -0
  188. package/src/services/hints.js +47 -0
  189. package/src/services/hints.test.js +110 -0
  190. package/src/services/patternRegistry.js +69 -1
  191. package/src/services/patternRegistry.test.js +112 -1
  192. package/src/services/reverseGeocode.js +4 -0
  193. package/src/services/reverseGeocode.test.js +11 -1
  194. package/src/services/symbolRegistry.js +152 -17
  195. package/src/services/symbolRegistry.test.js +141 -31
  196. package/src/types.js +93 -16
  197. package/src/utils/constrainKeyboardFocus.js +5 -5
  198. package/src/utils/detectInterfaceType.js +27 -5
  199. package/src/utils/detectInterfaceType.test.js +29 -3
  200. package/src/utils/mapStateSync.js +2 -2
  201. package/src/utils/mapStateSync.test.js +18 -0
  202. package/src/utils/patternUtils.js +4 -67
  203. package/src/utils/patternUtils.test.js +1 -123
  204. package/src/utils/symbolUtils.js +11 -13
  205. package/src/utils/symbolUtils.test.js +18 -26
  206. package/webpack.dev.mjs +4 -0
  207. package/webpack.umd.mjs +9 -6
  208. package/plugins/beta/datasets/adapters/maplibre/dist/esm/im-datasets-ml-adapter.js +0 -1
  209. package/plugins/beta/datasets/adapters/maplibre/dist/umd/im-datasets-ml-adapter.js +0 -2
  210. package/plugins/beta/datasets/adapters/maplibre/dist/umd/index.js +0 -1
  211. package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +0 -2
  212. package/plugins/beta/datasets/dist/umd/index.js +0 -2
  213. package/plugins/interact/dist/css/index.css +0 -1
  214. package/plugins/interact/src/interact.scss +0 -24
  215. /package/plugins/beta/datasets/{adapters/maplibre/dist → dist/adapters/maplibre}/esm/index.js +0 -0
  216. /package/plugins/beta/datasets/{adapters/maplibre/dist/umd/im-datasets-ml-adapter.js.LICENSE.txt → dist/umd/maplibre/im-datasets-maplibre-adapter.js.LICENSE.txt} +0 -0
  217. /package/plugins/beta/datasets/dist/umd/{im-datasets-plugin.js.LICENSE.txt → maplibre/im-datasets-plugin.js.LICENSE.txt} +0 -0
  218. /package/plugins/beta/datasets/dist/umd/{index.js.LICENSE.txt → maplibre/index.js.LICENSE.txt} +0 -0
@@ -0,0 +1,187 @@
1
+ import { useEffect, useRef } from 'react'
2
+ import { EVENTS } from '../../../../src/config/events.js'
3
+ import { isStandaloneLabel } from '../../../../src/utils/symbolUtils.js'
4
+ import { buildLayerConfigMap } from '../utils/featureQueries.js'
5
+
6
+ const getFeatureId = (feature, config) =>
7
+ config ? (feature.properties?.[config.idProperty] ?? feature.id) : null
8
+
9
+ const isInViewport = (el) => {
10
+ const container = el.closest('.im-c-viewport__markers')
11
+ if (!container) {
12
+ return false
13
+ }
14
+ const containerRect = container.getBoundingClientRect()
15
+ const { left, right, top, bottom } = el.getBoundingClientRect()
16
+ return right > containerRect.left && left < containerRect.right &&
17
+ bottom > containerRect.top && top < containerRect.bottom
18
+ }
19
+
20
+ const collectVisibleMarkers = (markers) => {
21
+ const items = []
22
+ for (const marker of markers.items) {
23
+ if (!marker.label) { continue }
24
+ const el = markers.markerRefs?.get(marker.id)
25
+ if (!isStandaloneLabel(marker) && el && isInViewport(el)) {
26
+ items.push({ id: marker.id, label: marker.label })
27
+ }
28
+ }
29
+ return items
30
+ }
31
+
32
+ const toFeatureItem = (feature, layerConfigMap, seenIds) => {
33
+ const config = layerConfigMap[feature.layer?.id]
34
+ if (!config?.labelProperty) {
35
+ return null
36
+ }
37
+ const id = getFeatureId(feature, config)
38
+ const stringId = id == null ? null : String(id)
39
+ if (stringId == null || seenIds.has(stringId)) {
40
+ return null
41
+ }
42
+ seenIds.add(stringId)
43
+ const label = feature.properties?.[config.labelProperty] ?? stringId
44
+ return { id: stringId, label }
45
+ }
46
+
47
+ const collectVisibleFeatures = (mapProvider, layers) => {
48
+ const items = []
49
+ const seenIds = new Set()
50
+ const layerIds = layers.map(layer => layer.layerId)
51
+ const layerConfigMap = buildLayerConfigMap(layers)
52
+ const features = mapProvider.getVisibleFeatures(layerIds)
53
+ for (const feature of features) {
54
+ const item = toFeatureItem(feature, layerConfigMap, seenIds)
55
+ if (item) {
56
+ items.push(item)
57
+ }
58
+ }
59
+ return items
60
+ }
61
+
62
+ const findFeatureById = (features, layerConfigMap, targetId) => {
63
+ for (const feature of features) {
64
+ const config = layerConfigMap[feature.layer?.id]
65
+ const rawId = getFeatureId(feature, config)
66
+ if (rawId != null && String(rawId) === String(targetId)) {
67
+ return { feature, config, rawId }
68
+ }
69
+ }
70
+ return null
71
+ }
72
+
73
+ /**
74
+ * Rebuilds the keyboard-navigable item list whenever the map moves or data changes.
75
+ * Collects visible markers (by DOM visibility) and visible features (by viewport query),
76
+ * then emits MAP_SET_FEATURES so the listbox stays in sync with what the user can see.
77
+ */
78
+ function useItemListSync ({ markers, interactionModes, layers, mapProvider, multiSelect, eventBus }) {
79
+ useEffect(() => {
80
+ const handleMoveEnd = () => {
81
+ const items = []
82
+ if (interactionModes?.includes('selectMarker')) {
83
+ items.push(...collectVisibleMarkers(markers))
84
+ }
85
+ if (interactionModes?.includes('selectFeature') && layers.length > 0) {
86
+ items.push(...collectVisibleFeatures(mapProvider, layers))
87
+ }
88
+ eventBus.emit(EVENTS.MAP_SET_FEATURES, { items, multiselectable: multiSelect })
89
+ }
90
+ handleMoveEnd()
91
+ eventBus.on(EVENTS.MAP_MOVE_END, handleMoveEnd)
92
+ eventBus.on(EVENTS.MAP_DATA_CHANGE, handleMoveEnd)
93
+ return () => {
94
+ eventBus.off(EVENTS.MAP_MOVE_END, handleMoveEnd)
95
+ eventBus.off(EVENTS.MAP_DATA_CHANGE, handleMoveEnd)
96
+ }
97
+ }, [markers, interactionModes, layers, mapProvider, multiSelect, eventBus])
98
+ }
99
+
100
+ /**
101
+ * Listens for MAP_SET_ACTIVE_FEATURE and resolves the active item to its full feature/marker data,
102
+ * storing it in both a ref (for synchronous access) and plugin state (for highlight rendering).
103
+ * Shows the keyboard cursor ring without firing interact:selectionchange — committing the item
104
+ * to the real selection only happens when the user presses Enter/Space.
105
+ */
106
+ function useActiveItemHandler ({ markers, interactionModes, layers, mapProvider, eventBus, dispatch, listboxActiveItemRef }) {
107
+ useEffect(() => {
108
+ const handle = ({ id }) => {
109
+ if (id === null) {
110
+ listboxActiveItemRef.current = null
111
+ dispatch({ type: 'SET_LISTBOX_ACTIVE', payload: null })
112
+ return
113
+ }
114
+ const markerMatch = markers.items.find(m => m.id === id)
115
+ if (markerMatch) {
116
+ listboxActiveItemRef.current = { id, isMarker: true }
117
+ dispatch({ type: 'SET_LISTBOX_ACTIVE', payload: null })
118
+ return
119
+ }
120
+ if (interactionModes?.includes('selectFeature') && layers.length > 0) {
121
+ const layerIds = layers.map(layer => layer.layerId)
122
+ const layerConfigMap = buildLayerConfigMap(layers)
123
+ const features = mapProvider.getVisibleFeatures(layerIds)
124
+ const match = findFeatureById(features, layerConfigMap, id)
125
+ if (match) {
126
+ const payload = {
127
+ featureId: match.rawId,
128
+ layerId: match.config.layerId,
129
+ idProperty: match.config.idProperty,
130
+ geometry: match.feature.geometry
131
+ }
132
+ listboxActiveItemRef.current = { id, isMarker: false, ...payload, properties: match.feature.properties }
133
+ dispatch({ type: 'SET_LISTBOX_ACTIVE', payload })
134
+ }
135
+ }
136
+ }
137
+ eventBus.on(EVENTS.MAP_SET_ACTIVE_FEATURE, handle)
138
+ return () => { eventBus.off(EVENTS.MAP_SET_ACTIVE_FEATURE, handle) }
139
+ }, [markers, interactionModes, layers, mapProvider, eventBus, dispatch, listboxActiveItemRef])
140
+ }
141
+
142
+ /**
143
+ * Handles MAP_SELECT_FEATURE (Enter/Space keypress) by promoting the currently active
144
+ * listbox item to a confirmed selection, dispatching TOGGLE_SELECTED_FEATURES or
145
+ * TOGGLE_SELECTED_MARKERS and triggering interact:selectionchange downstream.
146
+ */
147
+ function useSelectItemHandler ({ eventBus, dispatch, listboxActiveItemRef, multiSelect }) {
148
+ useEffect(() => {
149
+ const handleConfirm = () => {
150
+ const item = listboxActiveItemRef.current
151
+ if (!item) {
152
+ return
153
+ }
154
+ if (item.isMarker) {
155
+ dispatch({ type: 'TOGGLE_SELECTED_MARKERS', payload: { markerId: item.id, multiSelect } })
156
+ } else {
157
+ const { featureId, layerId, idProperty, geometry, properties } = item
158
+ dispatch({
159
+ type: 'TOGGLE_SELECTED_FEATURES',
160
+ payload: { featureId, layerId, idProperty, geometry, properties, multiSelect, replaceAll: !multiSelect }
161
+ })
162
+ }
163
+ }
164
+ eventBus.on(EVENTS.MAP_SELECT_FEATURE, handleConfirm)
165
+ return () => { eventBus.off(EVENTS.MAP_SELECT_FEATURE, handleConfirm) }
166
+ }, [eventBus, dispatch, listboxActiveItemRef, multiSelect])
167
+ }
168
+
169
+ /**
170
+ * Orchestrates the keyboard-accessible listbox for the interact plugin.
171
+ *
172
+ * Composes three concerns:
173
+ * - Item list sync — keeps the listbox populated with currently visible markers and features
174
+ * - Active item resolution — translates a listbox cursor position into full feature/marker data
175
+ * - Selection confirmation — commits the active item to the selection on Enter/Space
176
+ *
177
+ * @param {{ mapState: object, pluginState: object, services: object, mapProvider: object }} params
178
+ */
179
+ export function useMapItemList ({ mapState, pluginState, services, mapProvider }) {
180
+ const { markers } = mapState
181
+ const { dispatch, interactionModes, layers, multiSelect } = pluginState
182
+ const { eventBus } = services
183
+ const listboxActiveItemRef = useRef(null)
184
+ useItemListSync({ markers, interactionModes, layers, mapProvider, multiSelect, eventBus })
185
+ useActiveItemHandler({ markers, interactionModes, layers, mapProvider, eventBus, dispatch, listboxActiveItemRef })
186
+ useSelectItemHandler({ eventBus, dispatch, listboxActiveItemRef, multiSelect })
187
+ }