@defra/interactive-map 0.0.43-alpha → 0.0.44-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.
- package/dist/css/index.css +1 -1
- package/dist/esm/im-core.js +1 -1
- package/dist/esm/im-shell.js +1 -1
- package/dist/umd/im-core.js +1 -1
- package/dist/umd/index.js +1 -1
- package/docs/api.md +16 -8
- package/docs/plugins/draw.md +1 -1
- package/package.json +1 -1
- package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
- package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ol/dist/esm/im-draw-ol-plugin.js +1 -1
- package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -1
- package/plugins/beta/map-styles/dist/umd/index.js +1 -1
- package/plugins/datasets/dist/css/index.css +1 -1
- package/plugins/datasets/dist/esm/im-datasets-plugin.js +1 -1
- package/plugins/datasets/dist/umd/im-datasets-plugin.js +1 -1
- package/plugins/datasets/src/components/LayersMenu/Layers.module.scss +1 -0
- package/plugins/datasets/src/initialise/DatasetsInit.jsx +2 -2
- package/plugins/datasets/src/initialise/DatasetsInit.test.jsx +6 -5
- package/plugins/draw/dist/esm/im-draw-ml-adapter.js +1 -1
- package/plugins/draw/dist/esm/im-draw-ol-adapter.js +1 -1
- package/plugins/draw/dist/esm/im-draw-plugin.js +1 -1
- package/plugins/draw/dist/esm/index.js +1 -1
- package/plugins/draw/dist/umd/im-draw-ml-adapter.js +1 -1
- package/plugins/draw/dist/umd/im-draw-ol-adapter.js +1 -1
- package/plugins/draw/dist/umd/im-draw-plugin.js +1 -1
- package/plugins/draw/dist/umd/index.js +1 -1
- package/plugins/draw/src/DrawInit.jsx +31 -26
- package/plugins/draw/src/DrawInit.test.jsx +55 -12
- package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.js +113 -114
- package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.test.js +82 -9
- package/plugins/draw/src/adapters/maplibre/drawEvents.js +3 -1
- package/plugins/draw/src/adapters/maplibre/modes/createDrawMode.test.js +1 -1
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/__helpers__/harness.js +18 -9
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/clickHandlers.js +9 -1
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/clickHandlers.test.js +11 -1
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.js +8 -2
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.test.js +35 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/pointerHandlers.js +29 -19
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/pointerHandlers.test.js +17 -2
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/undoHandlers.test.js +1 -1
- package/plugins/draw/src/adapters/maplibre/modes/drawPointMode.js +35 -29
- package/plugins/draw/src/adapters/maplibre/modes/drawPointMode.test.js +24 -6
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/keyboardHandlers.js +22 -20
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode/pointOperations.js +1 -1
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode.js +2 -2
- package/plugins/draw/src/adapters/maplibre/modes/editPointMode.test.js +3 -3
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/geometryHelpers.js +31 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/geometryHelpers.test.js +8 -1
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.js +38 -30
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.test.js +20 -3
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/pointerHandlers.js +5 -5
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.js +2 -2
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.test.js +2 -2
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.js +3 -3
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.test.js +7 -7
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.js +4 -4
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.test.js +14 -14
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexQueries.js +12 -32
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexQueries.test.js +10 -10
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.js +48 -22
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.test.js +74 -6
- package/plugins/draw/src/adapters/maplibre/utils/snapMovement.js +2 -2
- package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.js +6 -0
- package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.test.js +9 -0
- package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.js +15 -2
- package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.test.js +27 -1
- package/plugins/draw/src/adapters/openlayers/draw/DrawMode.test.js +1 -1
- package/plugins/draw/src/adapters/openlayers/draw/drawInput.js +31 -17
- package/plugins/draw/src/adapters/openlayers/draw/drawInput.test.js +55 -1
- package/plugins/draw/src/adapters/openlayers/draw/vertexPlacement.js +13 -7
- package/plugins/draw/src/adapters/openlayers/draw/vertexPlacement.test.js +7 -15
- package/plugins/draw/src/adapters/openlayers/edit/EditMode.js +36 -4
- package/plugins/draw/src/adapters/openlayers/edit/EditMode.test.js +41 -1
- package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.js +35 -25
- package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.test.js +40 -2
- package/plugins/draw/src/adapters/openlayers/edit/nudge.js +2 -2
- package/plugins/draw/src/adapters/openlayers/edit/nudge.test.js +2 -2
- package/plugins/draw/src/adapters/openlayers/point/drawPointMode.js +32 -57
- package/plugins/draw/src/adapters/openlayers/point/drawPointMode.test.js +14 -13
- package/plugins/draw/src/adapters/openlayers/point/editPointMode.js +1 -1
- package/plugins/draw/src/adapters/openlayers/point/editPointMode.test.js +17 -1
- package/plugins/draw/src/events.js +4 -4
- package/plugins/draw/src/events.test.js +1 -1
- package/plugins/draw/src/hooks/useSpatialList.js +180 -0
- package/plugins/draw/src/hooks/useSpatialList.test.js +339 -0
- package/plugins/draw/src/utils/spatial.js +1 -31
- package/plugins/draw/src/utils/spatial.test.js +1 -24
- package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
- package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
- package/plugins/interact/dist/umd/index.js +1 -1
- package/plugins/interact/src/InteractInit.jsx +2 -2
- package/plugins/interact/src/InteractInit.test.js +3 -3
- package/plugins/interact/src/events.js +5 -0
- package/plugins/interact/src/hooks/useAttachEvents.js +20 -0
- package/plugins/interact/src/hooks/useAttachEvents.test.js +44 -1
- package/plugins/interact/src/hooks/useCrossHairVisibility.js +4 -4
- package/plugins/interact/src/hooks/useCrossHairVisibility.test.js +7 -7
- package/plugins/interact/src/hooks/{useMapItemList.js → useSpatialList.js} +87 -52
- package/plugins/interact/src/hooks/{useMapItemList.test.js → useSpatialList.test.js} +152 -71
- package/plugins/interact/src/manifest.js +12 -1
- package/plugins/interact/src/manifest.test.js +20 -0
- package/plugins/interact/src/utils/spatial.js +1 -1
- package/providers/beta/openlayers/src/utils/queryFeatures.js +1 -1
- package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
- package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
- package/providers/maplibre/dist/umd/index.js +1 -1
- package/providers/maplibre/src/utils/labels.js +2 -2
- package/providers/maplibre/src/utils/labels.test.js +5 -5
- package/providers/maplibre/src/utils/spatial.js +0 -57
- package/providers/maplibre/src/utils/spatial.test.js +0 -27
- package/src/App/components/CrossHair/CrossHair.jsx +10 -4
- package/src/App/components/CrossHair/CrossHair.module.scss +16 -12
- package/src/App/components/CrossHair/CrossHair.test.jsx +9 -4
- package/src/App/components/Hints/Hints.jsx +3 -3
- package/src/App/components/Hints/Hints.test.jsx +3 -3
- package/src/App/components/MapButton/MapButton.module.scss +1 -2
- package/src/App/components/{MoveControls/MoveControls.jsx → MapControls/MapControls.jsx} +10 -10
- package/src/App/components/{MoveControls/MoveControls.module.scss → MapControls/MapControls.module.scss} +25 -25
- package/src/App/components/{MoveControls/MoveControls.test.jsx → MapControls/MapControls.test.jsx} +48 -48
- package/src/App/components/Markers/Markers.jsx +2 -2
- package/src/App/components/Markers/Markers.test.jsx +3 -3
- package/src/App/components/Markers/SymbolMarker.test.jsx +2 -2
- package/src/App/components/Viewport/MapStatus.jsx +1 -1
- package/src/App/components/Viewport/SpatialList.jsx +47 -0
- package/src/App/components/Viewport/{Features.module.scss → SpatialList.module.scss} +3 -3
- package/src/App/components/Viewport/{Features.test.jsx → SpatialList.test.jsx} +60 -43
- package/src/App/components/Viewport/Viewport.jsx +20 -10
- package/src/App/components/Viewport/Viewport.test.jsx +18 -2
- package/src/App/hooks/useCrossHairAPI.js +5 -5
- package/src/App/hooks/useCrossHairAPI.test.js +5 -5
- package/src/App/hooks/useHintsAPI.js +5 -5
- package/src/App/hooks/useSpatialListFocus.js +296 -0
- package/src/App/hooks/{useFeatureFocus.test.js → useSpatialListFocus.test.js} +318 -163
- package/src/App/hooks/useSpatialListItems.js +51 -0
- package/src/App/hooks/useSpatialListItems.test.js +217 -0
- package/src/App/initialiseApp.js +6 -3
- package/src/App/initialiseApp.test.js +11 -0
- package/src/App/registry/spatialListRegistry.js +104 -0
- package/src/App/registry/spatialListRegistry.test.js +218 -0
- package/src/App/store/AppProvider.jsx +3 -2
- package/src/config/appConfig.js +14 -14
- package/src/config/appConfig.test.js +19 -19
- package/src/config/defaults.js +2 -2
- package/src/config/events.js +8 -8
- package/src/scss/main.scss +2 -2
- package/src/test-utils.js +8 -0
- package/src/types.js +11 -9
- package/src/utils/findNearestItemInDirection.js +29 -0
- package/src/utils/findNearestItemInDirection.test.js +67 -0
- package/src/utils/globalAltShortcuts.js +12 -0
- package/src/utils/globalAltShortcuts.test.js +27 -0
- package/src/utils/spatialNavigate.js +49 -0
- package/src/utils/spatialNavigate.test.js +42 -0
- package/src/App/components/Viewport/Features.jsx +0 -49
- package/src/App/hooks/useFeatureFocus.js +0 -257
- package/src/App/hooks/useFeatureItems.js +0 -39
- package/src/App/hooks/useFeatureItems.test.js +0 -155
|
@@ -5,8 +5,10 @@ import { scaleFactor } from '../../../../src/config/appConfig.js'
|
|
|
5
5
|
import { buildLayerConfigMap } from '../utils/featureQueries.js'
|
|
6
6
|
import { getGeometryCenter } from '../utils/spatial.js'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// Only called after toFeatureItem's own `config?.labelProperty` guard, so config is always
|
|
9
|
+
// truthy here — no defensive null-config branch needed (that was only for findFeatureById's own
|
|
10
|
+
// direct-lookup path, since removed along with the mapProvider.getVisibleFeatures re-query it did).
|
|
11
|
+
const getFeatureId = (feature, config) => feature.properties?.[config.idProperty] ?? feature.id
|
|
10
12
|
|
|
11
13
|
const isInViewport = (el) => {
|
|
12
14
|
const container = el.closest('.im-c-viewport__markers')
|
|
@@ -40,7 +42,7 @@ const collectVisibleMarkers = (markers, mapProvider, mapSize) => {
|
|
|
40
42
|
if (!marker.label) { continue }
|
|
41
43
|
const el = markers.markerRefs?.get(marker.id)
|
|
42
44
|
if (!isStandaloneLabel(marker) && el && isInViewport(el)) {
|
|
43
|
-
const item = { id: marker.id, label: marker.label }
|
|
45
|
+
const item = { id: marker.id, label: marker.label, isMarker: true }
|
|
44
46
|
if (marker.coords) {
|
|
45
47
|
Object.assign(item, projectToScreen(mapProvider, mapSize, marker.coords))
|
|
46
48
|
}
|
|
@@ -55,14 +57,28 @@ const toFeatureItem = (feature, layerConfigMap, seenIds, mapProvider, mapSize) =
|
|
|
55
57
|
if (!config?.labelProperty) {
|
|
56
58
|
return null
|
|
57
59
|
}
|
|
58
|
-
const
|
|
59
|
-
const stringId =
|
|
60
|
+
const rawId = getFeatureId(feature, config)
|
|
61
|
+
const stringId = rawId == null ? null : String(rawId)
|
|
60
62
|
if (stringId == null || seenIds.has(stringId)) {
|
|
61
63
|
return null
|
|
62
64
|
}
|
|
63
65
|
seenIds.add(stringId)
|
|
64
66
|
const label = feature.properties?.[config.labelProperty] ?? stringId
|
|
65
|
-
|
|
67
|
+
// Keeps the full resolved shape (raw id, layer config, geometry, properties) alongside the
|
|
68
|
+
// listbox-facing id/label — not just for building the item, but so useActiveItemHandler below
|
|
69
|
+
// can resolve "what is this" from this same object later, without re-querying the map engine.
|
|
70
|
+
// Only id/label/x/y ever reach MAP_SET_SPATIAL_LIST itself (see toPublicItem) — the rest stays
|
|
71
|
+
// internal, in itemsRef.
|
|
72
|
+
const item = {
|
|
73
|
+
id: stringId,
|
|
74
|
+
label,
|
|
75
|
+
isMarker: false,
|
|
76
|
+
featureId: rawId,
|
|
77
|
+
layerId: config.layerId,
|
|
78
|
+
idProperty: config.idProperty,
|
|
79
|
+
geometry: feature.geometry,
|
|
80
|
+
properties: feature.properties
|
|
81
|
+
}
|
|
66
82
|
// Bbox-centre of the feature's geometry (polygon or line) — see getGeometryCenter's own doc
|
|
67
83
|
// for why a bbox centre rather than a true centroid. null when the feature carries no usable
|
|
68
84
|
// geometry (e.g. OpenLayers' getVisibleFeatures, currently a stub returning [] — see PR notes).
|
|
@@ -88,23 +104,24 @@ const collectVisibleFeatures = (mapProvider, layers, mapSize) => {
|
|
|
88
104
|
return items
|
|
89
105
|
}
|
|
90
106
|
|
|
91
|
-
const findFeatureById = (features, layerConfigMap, targetId) => {
|
|
92
|
-
for (const feature of features) {
|
|
93
|
-
const config = layerConfigMap[feature.layer?.id]
|
|
94
|
-
const rawId = getFeatureId(feature, config)
|
|
95
|
-
if (rawId != null && String(rawId) === String(targetId)) {
|
|
96
|
-
return { feature, config, rawId }
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return null
|
|
100
|
-
}
|
|
101
|
-
|
|
102
107
|
/**
|
|
103
|
-
* Rebuilds the keyboard-navigable item list whenever the map moves or data changes.
|
|
104
|
-
*
|
|
105
|
-
*
|
|
108
|
+
* Rebuilds the keyboard-navigable item list whenever the map moves or data changes. Collects
|
|
109
|
+
* visible markers (by DOM visibility) and visible features (by viewport query), keeps the
|
|
110
|
+
* result in itemsRef for useActiveItemHandler to resolve against later, and tells
|
|
111
|
+
* spatialListRegistry its items have changed so the shared listbox stays in sync with what's
|
|
112
|
+
* visible. SpatialList.jsx/useSpatialListItems.js only ever render id/label/x/y from each item — the
|
|
113
|
+
* rest (isMarker, geometry, properties, layer config) rides along unused there, but is what
|
|
114
|
+
* lets useActiveItemHandler resolve "what is this" from the same object later, with nothing to
|
|
115
|
+
* re-derive and no separate lean/rich shape to keep in sync.
|
|
116
|
+
*
|
|
117
|
+
* interact no longer emits MAP_SET_SPATIAL_LIST directly — spatialListRegistry owns that (see its
|
|
118
|
+
* own doc comment for why: a single "whoever emits last wins" event doesn't scale once more
|
|
119
|
+
* than one plugin, e.g. draw mid-edit, needs to contribute to or take over the same list).
|
|
106
120
|
*/
|
|
107
|
-
function useItemListSync ({ markers, mapSize, interactionModes, layers, mapProvider, multiSelect, eventBus }) {
|
|
121
|
+
function useItemListSync ({ markers, mapSize, interactionModes, layers, mapProvider, multiSelect, spatialListRegistry, eventBus, itemsRef }) {
|
|
122
|
+
const multiSelectRef = useRef(multiSelect)
|
|
123
|
+
multiSelectRef.current = multiSelect // always-current for the provider's getItems below, same convention as itemsRef
|
|
124
|
+
|
|
108
125
|
useEffect(() => {
|
|
109
126
|
const handleMoveEnd = () => {
|
|
110
127
|
const items = []
|
|
@@ -114,7 +131,8 @@ function useItemListSync ({ markers, mapSize, interactionModes, layers, mapProvi
|
|
|
114
131
|
if (interactionModes?.includes('selectFeature') && layers.length > 0) {
|
|
115
132
|
items.push(...collectVisibleFeatures(mapProvider, layers, mapSize))
|
|
116
133
|
}
|
|
117
|
-
|
|
134
|
+
itemsRef.current = items
|
|
135
|
+
spatialListRegistry.notifyItemsChanged('interact')
|
|
118
136
|
}
|
|
119
137
|
handleMoveEnd()
|
|
120
138
|
eventBus.on(EVENTS.MAP_MOVE_END, handleMoveEnd)
|
|
@@ -123,16 +141,37 @@ function useItemListSync ({ markers, mapSize, interactionModes, layers, mapProvi
|
|
|
123
141
|
eventBus.off(EVENTS.MAP_MOVE_END, handleMoveEnd)
|
|
124
142
|
eventBus.off(EVENTS.MAP_DATA_CHANGE, handleMoveEnd)
|
|
125
143
|
}
|
|
126
|
-
}, [markers, mapSize, interactionModes, layers, mapProvider, multiSelect, eventBus])
|
|
144
|
+
}, [markers, mapSize, interactionModes, layers, mapProvider, multiSelect, spatialListRegistry, eventBus, itemsRef])
|
|
145
|
+
|
|
146
|
+
// Registers once, for the lifetime of the hook — getItems reads itemsRef/multiSelectRef
|
|
147
|
+
// fresh on every call, so there's never a need to re-register just because a prop changed;
|
|
148
|
+
// the effect above already pushes fresh data out via notifyItemsChanged. Declared after
|
|
149
|
+
// that effect so this registration's own immediate recompute (inside the registry) already
|
|
150
|
+
// sees whatever the effect above just computed on this same mount, rather than momentarily
|
|
151
|
+
// registering with empty items and correcting a moment later.
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
spatialListRegistry.registerItemProvider('interact', {
|
|
154
|
+
getItems: () => ({ items: itemsRef.current, multiselectable: multiSelectRef.current, label: 'Map features' })
|
|
155
|
+
})
|
|
156
|
+
return () => { spatialListRegistry.unregisterItemProvider('interact') }
|
|
157
|
+
}, [spatialListRegistry, itemsRef])
|
|
127
158
|
}
|
|
128
159
|
|
|
129
160
|
/**
|
|
130
|
-
* Listens for
|
|
161
|
+
* Listens for MAP_SET_ACTIVE_ITEM and resolves the active item to its full feature/marker data,
|
|
131
162
|
* storing it in both a ref (for synchronous access) and plugin state (for highlight rendering).
|
|
132
163
|
* Shows the keyboard cursor ring without firing interact:selectionchange — committing the item
|
|
133
164
|
* to the real selection only happens when the user presses Enter/Space.
|
|
165
|
+
*
|
|
166
|
+
* Resolves purely by looking the id up in itemsRef (the same list useItemListSync just built) —
|
|
167
|
+
* deliberately not a fresh mapProvider.getVisibleFeatures() query. This fires on every roving-
|
|
168
|
+
* tabindex move (every arrow-key press while browsing the list), so re-querying the map engine
|
|
169
|
+
* here — as an earlier version of this hook did — meant every keystroke re-ran the same query
|
|
170
|
+
* useItemListSync had just run moments before, plus a second linear scan through the result, to
|
|
171
|
+
* re-derive data already computed once and discarded. A stale/out-of-range id (e.g. the map
|
|
172
|
+
* panned since the list was built) simply resolves to nothing, same as before.
|
|
134
173
|
*/
|
|
135
|
-
function useActiveItemHandler ({
|
|
174
|
+
function useActiveItemHandler ({ itemsRef, eventBus, dispatch, listboxActiveItemRef }) {
|
|
136
175
|
useEffect(() => {
|
|
137
176
|
const handle = ({ id }) => {
|
|
138
177
|
if (id === null) {
|
|
@@ -140,36 +179,31 @@ function useActiveItemHandler ({ markers, interactionModes, layers, mapProvider,
|
|
|
140
179
|
dispatch({ type: 'SET_LISTBOX_ACTIVE', payload: null })
|
|
141
180
|
return
|
|
142
181
|
}
|
|
143
|
-
const
|
|
144
|
-
if (
|
|
182
|
+
const item = itemsRef.current.find(i => i.id === id)
|
|
183
|
+
if (!item) {
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
if (item.isMarker) {
|
|
145
187
|
listboxActiveItemRef.current = { id, isMarker: true }
|
|
146
188
|
dispatch({ type: 'SET_LISTBOX_ACTIVE', payload: null })
|
|
147
189
|
return
|
|
148
190
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (match) {
|
|
155
|
-
const payload = {
|
|
156
|
-
featureId: match.rawId,
|
|
157
|
-
layerId: match.config.layerId,
|
|
158
|
-
idProperty: match.config.idProperty,
|
|
159
|
-
geometry: match.feature.geometry
|
|
160
|
-
}
|
|
161
|
-
listboxActiveItemRef.current = { id, isMarker: false, ...payload, properties: match.feature.properties }
|
|
162
|
-
dispatch({ type: 'SET_LISTBOX_ACTIVE', payload })
|
|
163
|
-
}
|
|
191
|
+
const payload = {
|
|
192
|
+
featureId: item.featureId,
|
|
193
|
+
layerId: item.layerId,
|
|
194
|
+
idProperty: item.idProperty,
|
|
195
|
+
geometry: item.geometry
|
|
164
196
|
}
|
|
197
|
+
listboxActiveItemRef.current = { id, isMarker: false, ...payload, properties: item.properties }
|
|
198
|
+
dispatch({ type: 'SET_LISTBOX_ACTIVE', payload })
|
|
165
199
|
}
|
|
166
|
-
eventBus.on(EVENTS.
|
|
167
|
-
return () => { eventBus.off(EVENTS.
|
|
168
|
-
}, [
|
|
200
|
+
eventBus.on(EVENTS.MAP_SET_ACTIVE_ITEM, handle)
|
|
201
|
+
return () => { eventBus.off(EVENTS.MAP_SET_ACTIVE_ITEM, handle) }
|
|
202
|
+
}, [itemsRef, eventBus, dispatch, listboxActiveItemRef])
|
|
169
203
|
}
|
|
170
204
|
|
|
171
205
|
/**
|
|
172
|
-
* Handles
|
|
206
|
+
* Handles MAP_SELECT_ITEM (Enter/Space keypress) by promoting the currently active
|
|
173
207
|
* listbox item to a confirmed selection, dispatching TOGGLE_SELECTED_FEATURES or
|
|
174
208
|
* TOGGLE_SELECTED_MARKERS and triggering interact:selectionchange downstream.
|
|
175
209
|
*/
|
|
@@ -190,8 +224,8 @@ function useSelectItemHandler ({ eventBus, dispatch, listboxActiveItemRef, multi
|
|
|
190
224
|
})
|
|
191
225
|
}
|
|
192
226
|
}
|
|
193
|
-
eventBus.on(EVENTS.
|
|
194
|
-
return () => { eventBus.off(EVENTS.
|
|
227
|
+
eventBus.on(EVENTS.MAP_SELECT_ITEM, handleConfirm)
|
|
228
|
+
return () => { eventBus.off(EVENTS.MAP_SELECT_ITEM, handleConfirm) }
|
|
195
229
|
}, [eventBus, dispatch, listboxActiveItemRef, multiSelect])
|
|
196
230
|
}
|
|
197
231
|
|
|
@@ -203,14 +237,15 @@ function useSelectItemHandler ({ eventBus, dispatch, listboxActiveItemRef, multi
|
|
|
203
237
|
* - Active item resolution — translates a listbox cursor position into full feature/marker data
|
|
204
238
|
* - Selection confirmation — commits the active item to the selection on Enter/Space
|
|
205
239
|
*
|
|
206
|
-
* @param {{ mapState: object, pluginState: object, services: object, mapProvider: object }} params
|
|
240
|
+
* @param {{ mapState: object, pluginState: object, services: object, mapProvider: object, spatialListRegistry: object }} params
|
|
207
241
|
*/
|
|
208
|
-
export function
|
|
242
|
+
export function useSpatialList ({ mapState, pluginState, services, mapProvider, spatialListRegistry }) {
|
|
209
243
|
const { markers, mapSize } = mapState
|
|
210
244
|
const { dispatch, interactionModes, layers, multiSelect } = pluginState
|
|
211
245
|
const { eventBus } = services
|
|
212
246
|
const listboxActiveItemRef = useRef(null)
|
|
213
|
-
|
|
214
|
-
|
|
247
|
+
const itemsRef = useRef([])
|
|
248
|
+
useItemListSync({ markers, mapSize, interactionModes, layers, mapProvider, multiSelect, spatialListRegistry, eventBus, itemsRef })
|
|
249
|
+
useActiveItemHandler({ itemsRef, eventBus, dispatch, listboxActiveItemRef })
|
|
215
250
|
useSelectItemHandler({ eventBus, dispatch, listboxActiveItemRef, multiSelect })
|
|
216
251
|
}
|