@defra/interactive-map 0.0.15-alpha → 0.0.16-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/assets/css/docusaurus.css +104 -0
- package/assets/images/favicon.svg +1 -0
- package/assets/images/hero.png +0 -0
- package/dist/esm/im-core.js +1 -1
- package/dist/umd/im-core.js +1 -1
- package/dist/umd/index.js +1 -1
- package/docs/api/slot-map.svg +1 -0
- package/docs/api/slots.md +89 -6
- package/docs/api.md +1 -1
- package/docs/architecture.md +3 -1
- package/docs/{demo.mdx → examples.mdx} +1 -1
- package/docs/getting-started.md +1 -3
- package/docs/index.mdx +42 -0
- package/docs/plugins/interact.md +176 -55
- package/docs/plugins/map-styles.md +64 -7
- package/docs/plugins/search.md +207 -63
- package/docs/plugins.md +7 -15
- package/docusaurus.config.cjs +34 -34
- package/jest.setup.js +1 -1
- package/package.json +5 -4
- package/plugins/beta/datasets/src/DatasetsInit.jsx +1 -1
- package/plugins/beta/datasets/src/api/addDataset.js +1 -1
- package/plugins/beta/datasets/src/api/hideDataset.js +1 -1
- package/plugins/beta/datasets/src/api/hideFeatures.js +1 -1
- package/plugins/beta/datasets/src/api/removeDataset.js +1 -1
- package/plugins/beta/datasets/src/api/showDataset.js +1 -1
- package/plugins/beta/datasets/src/api/showFeatures.js +1 -1
- package/plugins/beta/datasets/src/datasets.js +4 -4
- package/plugins/beta/datasets/src/defaults.js +1 -1
- package/plugins/beta/datasets/src/fetch/createDynamicSource.js +5 -5
- package/plugins/beta/datasets/src/handleSetMapStyle.js +1 -1
- package/plugins/beta/datasets/src/manifest.js +3 -3
- package/plugins/beta/datasets/src/mapLayers.js +2 -3
- package/plugins/beta/datasets/src/panels/Key.jsx +31 -29
- package/plugins/beta/datasets/src/panels/Layers.jsx +8 -9
- package/plugins/beta/datasets/src/utils/bbox.js +4 -4
- package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
- package/plugins/beta/draw-es/src/DrawInit.jsx +16 -16
- package/plugins/beta/draw-es/src/api/addFeature.js +3 -3
- package/plugins/beta/draw-es/src/api/deleteFeature.js +3 -3
- package/plugins/beta/draw-es/src/api/editFeature.js +3 -3
- package/plugins/beta/draw-es/src/api/newPolygon.js +3 -3
- package/plugins/beta/draw-es/src/events.js +52 -20
- package/plugins/beta/draw-es/src/events.test.js +301 -0
- package/plugins/beta/draw-es/src/graphic.js +1 -1
- package/plugins/beta/draw-es/src/manifest.js +4 -4
- package/plugins/beta/draw-es/src/reducer.js +1 -1
- package/plugins/beta/draw-es/src/sketchViewModel.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-ml/src/DrawInit.jsx +49 -52
- package/plugins/beta/draw-ml/src/api/deleteFeature.js +1 -1
- package/plugins/beta/draw-ml/src/api/editFeature.js +8 -5
- package/plugins/beta/draw-ml/src/api/newLine.js +0 -1
- package/plugins/beta/draw-ml/src/api/newPolygon.js +0 -1
- package/plugins/beta/draw-ml/src/api/split.js +4 -4
- package/plugins/beta/draw-ml/src/defaults.js +1 -1
- package/plugins/beta/draw-ml/src/events.js +8 -6
- package/plugins/beta/draw-ml/src/manifest.js +15 -15
- package/plugins/beta/draw-ml/src/mapboxDraw.js +1 -1
- package/plugins/beta/draw-ml/src/mapboxSnap.js +17 -18
- package/plugins/beta/draw-ml/src/modes/createDrawMode.js +31 -31
- package/plugins/beta/draw-ml/src/modes/disabledMode.js +1 -1
- package/plugins/beta/draw-ml/src/modes/editVertex/touchHandlers.js +11 -11
- package/plugins/beta/draw-ml/src/modes/editVertex/undoHandlers.js +7 -7
- package/plugins/beta/draw-ml/src/modes/editVertex/vertexOperations.js +8 -8
- package/plugins/beta/draw-ml/src/modes/editVertex/vertexQueries.js +7 -7
- package/plugins/beta/draw-ml/src/modes/editVertexMode.js +32 -24
- package/plugins/beta/draw-ml/src/reducer.js +1 -1
- package/plugins/beta/draw-ml/src/undoStack.js +4 -4
- package/plugins/beta/draw-ml/src/utils/snapHelpers.js +12 -12
- package/plugins/beta/draw-ml/src/utils/spatial.js +11 -11
- package/plugins/beta/frame/src/Frame.jsx +4 -4
- package/plugins/beta/frame/src/FrameInit.jsx +4 -4
- package/plugins/beta/frame/src/api/addFrame.js +1 -1
- package/plugins/beta/frame/src/api/editFeature.js +1 -1
- package/plugins/beta/frame/src/config.js +1 -1
- package/plugins/beta/frame/src/manifest.js +3 -3
- package/plugins/beta/frame/src/reducer.js +1 -1
- package/plugins/beta/frame/src/utils.js +1 -1
- package/plugins/beta/map-styles/src/MapStyles.jsx +18 -18
- package/plugins/beta/scale-bar/src/ScaleBar.jsx +5 -5
- package/plugins/beta/use-location/src/UseLocation.jsx +1 -1
- package/plugins/beta/use-location/src/defaults.js +1 -1
- package/plugins/beta/use-location/src/events.js +3 -3
- package/plugins/interact/src/InteractInit.jsx +1 -2
- package/plugins/interact/src/api/enable.js +8 -5
- package/plugins/interact/src/api/enable.test.js +2 -2
- package/plugins/interact/src/api/selectFeature.js +4 -4
- package/plugins/interact/src/api/unselectFeature.js +5 -5
- package/plugins/interact/src/defaults.js +0 -1
- package/plugins/interact/src/events.test.js +15 -15
- package/plugins/interact/src/hooks/useHighlightSync.js +1 -1
- package/plugins/interact/src/hooks/useInteractionHandlers.js +2 -2
- package/plugins/interact/src/hooks/useInteractionHandlers.test.js +5 -5
- package/plugins/interact/src/manifest.js +2 -2
- package/plugins/interact/src/manifest.test.js +3 -4
- package/plugins/interact/src/reducer.js +3 -3
- package/plugins/interact/src/reducer.test.js +0 -1
- package/plugins/interact/src/utils/spatial.js +10 -10
- package/plugins/interact/src/utils/spatial.test.js +14 -14
- package/plugins/search/dist/css/index.css +1 -1
- package/plugins/search/dist/esm/im-search-plugin.js +1 -1
- package/plugins/search/dist/esm/index.js +1 -1
- package/plugins/search/dist/umd/im-search-plugin.js +1 -1
- package/plugins/search/dist/umd/index.js +1 -1
- package/plugins/search/src/Search.jsx +7 -6
- package/plugins/search/src/Search.test.jsx +23 -23
- package/plugins/search/src/components/CloseButton/CloseButton.jsx +15 -15
- package/plugins/search/src/components/CloseButton/CloseButton.test.jsx +2 -2
- package/plugins/search/src/components/Form/Form.jsx +14 -14
- package/plugins/search/src/components/Form/Form.test.jsx +11 -11
- package/plugins/search/src/components/OpenButton/OpenButton.jsx +16 -15
- package/plugins/search/src/components/OpenButton/OpenButton.test.jsx +6 -2
- package/plugins/search/src/components/SubmitButton/SubmitButton.jsx +15 -15
- package/plugins/search/src/components/Suggestions/Suggestions.jsx +6 -6
- package/plugins/search/src/components/Suggestions/Suggestions.test.jsx +4 -4
- package/plugins/search/src/datasets.js +12 -13
- package/plugins/search/src/datasets.test.js +1 -1
- package/plugins/search/src/defaults.js +1 -1
- package/plugins/search/src/events/fetchSuggestions.js +3 -3
- package/plugins/search/src/events/fetchSuggestions.test.js +1 -1
- package/plugins/search/src/events/formHandlers.js +3 -3
- package/plugins/search/src/events/formHandlers.test.js +1 -1
- package/plugins/search/src/events/index.js +2 -2
- package/plugins/search/src/events/index.test.js +2 -2
- package/plugins/search/src/events/inputHandlers.js +4 -4
- package/plugins/search/src/events/inputHandlers.test.js +1 -1
- package/plugins/search/src/events/suggestionHandlers.js +2 -2
- package/plugins/search/src/events/suggestionHandlers.test.js +1 -1
- package/plugins/search/src/index.js +2 -1
- package/plugins/search/src/index.test.js +3 -3
- package/plugins/search/src/manifest.js +6 -4
- package/plugins/search/src/reducer.js +1 -2
- package/plugins/search/src/reducer.test.js +2 -2
- package/plugins/search/src/search.scss +10 -3
- package/plugins/search/src/utils/parseOsNamesResults.js +1 -2
- package/plugins/search/src/utils/parseOsNamesResults.test.js +2 -2
- package/plugins/search/src/utils/updateMap.js +1 -1
- package/plugins/search/src/utils/updateMap.test.js +5 -5
- package/providers/beta/esri/dist/esm/im-esri-provider.js +1 -1
- package/providers/beta/esri/src/esriProvider.js +5 -5
- package/providers/beta/esri/src/utils/coords.js +1 -1
- package/providers/beta/esri/src/utils/esriFixes.js +1 -1
- package/providers/beta/esri/src/utils/query.js +4 -4
- package/providers/beta/esri/src/utils/spatial.js +1 -2
- package/providers/beta/esri/src/utils/spatial.test.js +4 -1
- package/providers/beta/open-names/src/utils/mapToLocationModel.test.js +1 -1
- package/providers/maplibre/src/appEvents.test.js +1 -1
- package/providers/maplibre/src/index.js +1 -1
- package/providers/maplibre/src/index.test.js +3 -5
- package/providers/maplibre/src/mapEvents.test.js +15 -5
- package/providers/maplibre/src/maplibreProvider.test.js +6 -2
- package/providers/maplibre/src/utils/calculateLinearTextSize.js +4 -4
- package/providers/maplibre/src/utils/calculateLinearTextSize.test.js +3 -3
- package/providers/maplibre/src/utils/detectWebgl.test.js +1 -1
- package/providers/maplibre/src/utils/highlightFeatures.js +2 -2
- package/providers/maplibre/src/utils/highlightFeatures.test.js +12 -6
- package/providers/maplibre/src/utils/labels.js +19 -20
- package/providers/maplibre/src/utils/labels.test.js +15 -13
- package/providers/maplibre/src/utils/maplibreFixes.test.js +1 -1
- package/providers/maplibre/src/utils/queryFeatures.js +6 -6
- package/providers/maplibre/src/utils/queryFeatures.test.js +13 -13
- package/providers/maplibre/src/utils/spatial.js +0 -1
- package/providers/maplibre/src/utils/spatial.test.js +26 -27
- package/src/App/registry/pluginRegistry.js +17 -0
- package/src/App/registry/pluginRegistry.test.js +33 -0
- package/src/App/renderer/mapButtons.js +3 -2
- package/src/App/store/appDispatchMiddleware.js +33 -1
- package/src/App/store/appDispatchMiddleware.test.js +250 -222
- package/src/config/appConfig.js +2 -2
- package/src/utils/logger.js +6 -0
- package/src/utils/logger.test.js +32 -0
- package/webpack.dev.mjs +22 -18
- package/docs/govuk-prototype.md +0 -23
- package/docs/index.md +0 -19
|
@@ -17,7 +17,7 @@ export const createUndoStack = (map) => {
|
|
|
17
17
|
* Push an undo operation onto the stack
|
|
18
18
|
* @param {Object} operation - { type, undo: Function, ...data }
|
|
19
19
|
*/
|
|
20
|
-
push(operation) {
|
|
20
|
+
push (operation) {
|
|
21
21
|
stack.push(operation)
|
|
22
22
|
fireChange()
|
|
23
23
|
},
|
|
@@ -26,7 +26,7 @@ export const createUndoStack = (map) => {
|
|
|
26
26
|
* Pop and return the last operation (does not execute it)
|
|
27
27
|
* @returns {Object|undefined} The operation or undefined if empty
|
|
28
28
|
*/
|
|
29
|
-
pop() {
|
|
29
|
+
pop () {
|
|
30
30
|
const op = stack.pop()
|
|
31
31
|
fireChange()
|
|
32
32
|
return op
|
|
@@ -35,7 +35,7 @@ export const createUndoStack = (map) => {
|
|
|
35
35
|
/**
|
|
36
36
|
* Clear all operations from the stack
|
|
37
37
|
*/
|
|
38
|
-
clear() {
|
|
38
|
+
clear () {
|
|
39
39
|
stack.length = 0
|
|
40
40
|
fireChange()
|
|
41
41
|
},
|
|
@@ -43,7 +43,7 @@ export const createUndoStack = (map) => {
|
|
|
43
43
|
/**
|
|
44
44
|
* Get current stack length
|
|
45
45
|
*/
|
|
46
|
-
get length() {
|
|
46
|
+
get length () {
|
|
47
47
|
return stack.length
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @param {maplibregl.Map} map - Map instance
|
|
9
9
|
* @returns {MapboxSnap|null} Snap instance or null
|
|
10
10
|
*/
|
|
11
|
-
export function getSnapInstance(map) {
|
|
11
|
+
export function getSnapInstance (map) {
|
|
12
12
|
return map?._snapInstance ?? null
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -17,7 +17,7 @@ export function getSnapInstance(map) {
|
|
|
17
17
|
* @param {MapboxSnap} snap - Snap instance
|
|
18
18
|
* @returns {boolean} True if snap is active with valid coordinates
|
|
19
19
|
*/
|
|
20
|
-
export function isSnapActive(snap) {
|
|
20
|
+
export function isSnapActive (snap) {
|
|
21
21
|
// Also check snap.status to ensure snap feature is enabled
|
|
22
22
|
return !!(snap?.status && snap?.snapStatus && snap.snapCoords?.length >= 2)
|
|
23
23
|
}
|
|
@@ -27,7 +27,7 @@ export function isSnapActive(snap) {
|
|
|
27
27
|
* @param {MapboxSnap} snap - Snap instance
|
|
28
28
|
* @returns {{ lng: number, lat: number }|null} Snapped coordinates or null
|
|
29
29
|
*/
|
|
30
|
-
export function getSnapLngLat(snap) {
|
|
30
|
+
export function getSnapLngLat (snap) {
|
|
31
31
|
if (!isSnapActive(snap)) {
|
|
32
32
|
return null
|
|
33
33
|
}
|
|
@@ -42,7 +42,7 @@ export function getSnapLngLat(snap) {
|
|
|
42
42
|
* @param {MapboxSnap} snap - Snap instance
|
|
43
43
|
* @returns {[number, number]|null} Snapped coordinates or null
|
|
44
44
|
*/
|
|
45
|
-
export function getSnapCoords(snap) {
|
|
45
|
+
export function getSnapCoords (snap) {
|
|
46
46
|
if (!isSnapActive(snap)) {
|
|
47
47
|
return null
|
|
48
48
|
}
|
|
@@ -56,7 +56,7 @@ export function getSnapCoords(snap) {
|
|
|
56
56
|
* @param {{ x: number, y: number }} point - Screen point
|
|
57
57
|
* @returns {boolean} True if snap was triggered
|
|
58
58
|
*/
|
|
59
|
-
export function triggerSnapAtPoint(snap, map, point) {
|
|
59
|
+
export function triggerSnapAtPoint (snap, map, point) {
|
|
60
60
|
if (!snap || !map || !snap.status) {
|
|
61
61
|
return false
|
|
62
62
|
}
|
|
@@ -72,7 +72,7 @@ export function triggerSnapAtPoint(snap, map, point) {
|
|
|
72
72
|
* @param {maplibregl.Map} map - Map instance
|
|
73
73
|
* @returns {boolean} True if snap was triggered
|
|
74
74
|
*/
|
|
75
|
-
export function triggerSnapAtCenter(snap, map) {
|
|
75
|
+
export function triggerSnapAtCenter (snap, map) {
|
|
76
76
|
// Don't trigger snap if library is disabled
|
|
77
77
|
if (!snap || !map || !snap.status) {
|
|
78
78
|
return false
|
|
@@ -89,7 +89,7 @@ export function triggerSnapAtCenter(snap, map) {
|
|
|
89
89
|
* @param {MapboxSnap} snap - Snap instance
|
|
90
90
|
* @param {maplibregl.Map} [map] - Optional map instance for direct layer control
|
|
91
91
|
*/
|
|
92
|
-
export function clearSnapIndicator(snap, map) {
|
|
92
|
+
export function clearSnapIndicator (snap, map) {
|
|
93
93
|
if (snap) {
|
|
94
94
|
snap.snapStatus = false
|
|
95
95
|
snap.snapCoords = null
|
|
@@ -116,7 +116,7 @@ export function clearSnapIndicator(snap, map) {
|
|
|
116
116
|
* Clear all snap state (for use between drag operations)
|
|
117
117
|
* @param {MapboxSnap} snap - Snap instance
|
|
118
118
|
*/
|
|
119
|
-
export function clearSnapState(snap) {
|
|
119
|
+
export function clearSnapState (snap) {
|
|
120
120
|
if (!snap) {
|
|
121
121
|
return
|
|
122
122
|
}
|
|
@@ -139,7 +139,7 @@ export function clearSnapState(snap) {
|
|
|
139
139
|
* @param {MapboxSnap} snap - Snap instance
|
|
140
140
|
* @returns {number} Snap radius in pixels (default 15)
|
|
141
141
|
*/
|
|
142
|
-
export function getSnapRadius(snap) {
|
|
142
|
+
export function getSnapRadius (snap) {
|
|
143
143
|
return snap?.options?.radius ?? 15
|
|
144
144
|
}
|
|
145
145
|
|
|
@@ -148,7 +148,7 @@ export function getSnapRadius(snap) {
|
|
|
148
148
|
* @param {object} state - Mode state with optional getSnapEnabled function
|
|
149
149
|
* @returns {boolean} True if snapping is enabled
|
|
150
150
|
*/
|
|
151
|
-
export function isSnapEnabled(state) {
|
|
151
|
+
export function isSnapEnabled (state) {
|
|
152
152
|
// Only return true if getSnapEnabled exists and explicitly returns true
|
|
153
153
|
if (typeof state?.getSnapEnabled !== 'function') {
|
|
154
154
|
return false
|
|
@@ -162,7 +162,7 @@ export function isSnapEnabled(state) {
|
|
|
162
162
|
* @param {MapboxSnap} snap - Snap instance
|
|
163
163
|
* @returns {object} Event with snapped lngLat or original event
|
|
164
164
|
*/
|
|
165
|
-
export function createSnappedEvent(e, snap) {
|
|
165
|
+
export function createSnappedEvent (e, snap) {
|
|
166
166
|
const lngLat = getSnapLngLat(snap)
|
|
167
167
|
if (!lngLat) {
|
|
168
168
|
return e
|
|
@@ -180,7 +180,7 @@ export function createSnappedEvent(e, snap) {
|
|
|
180
180
|
* @param {MapboxSnap} snap - Snap instance
|
|
181
181
|
* @returns {object|null} Synthetic event or null if no snap
|
|
182
182
|
*/
|
|
183
|
-
export function createSnappedClickEvent(map, snap) {
|
|
183
|
+
export function createSnappedClickEvent (map, snap) {
|
|
184
184
|
const lngLat = getSnapLngLat(snap)
|
|
185
185
|
if (!lngLat) {
|
|
186
186
|
return null
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
* @param {Feature<LineString>} line
|
|
29
29
|
* @param {number} extendDist (distance to extend in Turf units)
|
|
30
30
|
*/
|
|
31
|
-
function extendLine(line, extendDist = 1, units = 'meters') {
|
|
31
|
+
function extendLine (line, extendDist = 1, units = 'meters') {
|
|
32
32
|
const coords = line.geometry.coordinates
|
|
33
33
|
const result = []
|
|
34
34
|
|
|
@@ -113,17 +113,17 @@ const toTurfGeometry = (featureOrGeom) => {
|
|
|
113
113
|
|
|
114
114
|
switch (geom.type) {
|
|
115
115
|
case 'Polygon':
|
|
116
|
-
return turfPolygon(geom.coordinates)
|
|
116
|
+
return turfPolygon(geom.coordinates)
|
|
117
117
|
case 'MultiPolygon':
|
|
118
|
-
return turfMultiPolygon(geom.coordinates)
|
|
118
|
+
return turfMultiPolygon(geom.coordinates)
|
|
119
119
|
case 'LineString':
|
|
120
|
-
return turfLineString(geom.coordinates)
|
|
120
|
+
return turfLineString(geom.coordinates)
|
|
121
121
|
case 'MultiLineString':
|
|
122
|
-
return turfMultiLineString(geom.coordinates)
|
|
122
|
+
return turfMultiLineString(geom.coordinates)
|
|
123
123
|
case 'Point':
|
|
124
|
-
return turfPoint(geom.coordinates)
|
|
124
|
+
return turfPoint(geom.coordinates)
|
|
125
125
|
case 'MultiPoint':
|
|
126
|
-
return turfMultiPoint(geom.coordinates)
|
|
126
|
+
return turfMultiPoint(geom.coordinates)
|
|
127
127
|
default:
|
|
128
128
|
throw new Error(`Unsupported geometry type: ${geom.type}`)
|
|
129
129
|
}
|
|
@@ -251,8 +251,8 @@ export {
|
|
|
251
251
|
toTurfGeometry,
|
|
252
252
|
splitPolygon,
|
|
253
253
|
extendLine,
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
254
|
+
isNewCoordinate,
|
|
255
|
+
isValidClick,
|
|
256
|
+
isValidLineClick,
|
|
257
257
|
spatialNavigate
|
|
258
|
-
}
|
|
258
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useRef, useEffect, useState } from 'react'
|
|
2
2
|
import { computeInset } from './utils.js'
|
|
3
3
|
|
|
4
|
-
export function Frame({ appState, mapState, pluginState, mapProvider }) {
|
|
4
|
+
export function Frame ({ appState, mapState, pluginState, mapProvider }) {
|
|
5
5
|
const { actionsRef, mainRef, footerRef, viewportRef } = appState.layoutRefs
|
|
6
6
|
const { dispatch } = pluginState
|
|
7
7
|
const elRef = useRef(null)
|
|
@@ -87,7 +87,7 @@ export function Frame({ appState, mapState, pluginState, mapProvider }) {
|
|
|
87
87
|
const viewportRect = viewportEl.getBoundingClientRect()
|
|
88
88
|
|
|
89
89
|
// Calculate padding from viewport edges to frame edges
|
|
90
|
-
const scale = {small: 1, medium: 1.5, large: 2}[mapState.mapSize]
|
|
90
|
+
const scale = { small: 1, medium: 1.5, large: 2 }[mapState.mapSize]
|
|
91
91
|
|
|
92
92
|
const padding = {
|
|
93
93
|
top: (frameRect.top - viewportRect.top) / scale,
|
|
@@ -108,11 +108,11 @@ export function Frame({ appState, mapState, pluginState, mapProvider }) {
|
|
|
108
108
|
return (
|
|
109
109
|
<>
|
|
110
110
|
{/* Spacer */}
|
|
111
|
-
<div className=
|
|
111
|
+
<div className='im-c-frame-spacer' style={{ inset: parentInset }} ref={elRef} />
|
|
112
112
|
|
|
113
113
|
{/* Child */}
|
|
114
114
|
{childStyle && (
|
|
115
|
-
<div ref={displayRef} className=
|
|
115
|
+
<div ref={displayRef} className='im-c-frame-display' style={{ ...childStyle }} />
|
|
116
116
|
)}
|
|
117
117
|
</>
|
|
118
118
|
)
|
|
@@ -23,8 +23,8 @@ export const FrameInit = ({
|
|
|
23
23
|
// Attach events
|
|
24
24
|
useEffect(() => {
|
|
25
25
|
if (!isActive) {
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
28
|
|
|
29
29
|
// --- Done
|
|
30
30
|
frameDone.onClick = () => {
|
|
@@ -32,7 +32,7 @@ export const FrameInit = ({
|
|
|
32
32
|
frameEl: frameRefs.displayRef.current,
|
|
33
33
|
viewportEl: layoutRefs.viewportRef.current,
|
|
34
34
|
featureId: frame?.featureId,
|
|
35
|
-
scale: {small: 1, medium: 1.5, large: 2}[mapState.mapSize],
|
|
35
|
+
scale: { small: 1, medium: 1.5, large: 2 }[mapState.mapSize],
|
|
36
36
|
mapProvider
|
|
37
37
|
})
|
|
38
38
|
|
|
@@ -51,4 +51,4 @@ export const FrameInit = ({
|
|
|
51
51
|
frameCancel.onClick = null
|
|
52
52
|
}
|
|
53
53
|
}, [mapState.isMapReady, mode, breakpoint, frame, frameRefs, layoutRefs, mapProvider, dispatch, eventBus, frameDone, frameCancel])
|
|
54
|
-
}
|
|
54
|
+
}
|
|
@@ -6,8 +6,8 @@ import { addFrame } from './api/addFrame.js'
|
|
|
6
6
|
import { editFeature } from './api/editFeature.js'
|
|
7
7
|
|
|
8
8
|
const buttonSlots = {
|
|
9
|
-
mobile:
|
|
10
|
-
tablet:
|
|
9
|
+
mobile: { slot: 'actions', showLabel: true },
|
|
10
|
+
tablet: { slot: 'actions', showLabel: true },
|
|
11
11
|
desktop: { slot: 'actions', showLabel: true }
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -40,7 +40,7 @@ export const manifest = {
|
|
|
40
40
|
variant: 'primary',
|
|
41
41
|
hiddenWhen: ({ pluginState }) => !pluginState.frame,
|
|
42
42
|
...buttonSlots
|
|
43
|
-
},{
|
|
43
|
+
}, {
|
|
44
44
|
id: 'frameCancel',
|
|
45
45
|
label: 'Cancel',
|
|
46
46
|
variant: 'tertiary',
|
|
@@ -18,14 +18,14 @@ export const MapStyles = ({ mapState, pluginConfig, services, mapProvider }) =>
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
return (
|
|
21
|
-
<div className=
|
|
22
|
-
<div className=
|
|
23
|
-
<div className=
|
|
21
|
+
<div className='im-c-map-styles'>
|
|
22
|
+
<div className='im-c-map-styles__group'>
|
|
23
|
+
<div className='im-c-map-styles__inner'>
|
|
24
24
|
{mapStyles.filter(mapStyle => mapStyle.url).map(mapStyle => (
|
|
25
|
-
<div className=
|
|
26
|
-
<button className=
|
|
27
|
-
<div className=
|
|
28
|
-
<img src={mapStyle.thumbnail || undefined} alt=
|
|
25
|
+
<div className='im-c-map-styles__item' key={mapStyle.id}>
|
|
26
|
+
<button className='im-c-map-styles__button' aria-pressed={mapStyle.id === currentMapStyle.id} onClick={() => handleMapStyleClick(mapStyle)}>
|
|
27
|
+
<div className='im-c-map-styles__image'>
|
|
28
|
+
<img src={mapStyle.thumbnail || undefined} alt='' height='60' width='60' />
|
|
29
29
|
</div>
|
|
30
30
|
{mapStyle.label}
|
|
31
31
|
</button>
|
|
@@ -34,16 +34,16 @@ export const MapStyles = ({ mapState, pluginConfig, services, mapProvider }) =>
|
|
|
34
34
|
</div>
|
|
35
35
|
</div>
|
|
36
36
|
{supportsMapSizes && (
|
|
37
|
-
<div className=
|
|
38
|
-
<h3 className=
|
|
39
|
-
<div className=
|
|
40
|
-
{[
|
|
41
|
-
<div className=
|
|
42
|
-
<button className=
|
|
43
|
-
<div className=
|
|
44
|
-
<svg width=
|
|
45
|
-
<rect className=
|
|
46
|
-
<g style={{ transform: `scale(${scaleFactor[size]})`, transformOrigin:
|
|
37
|
+
<div className='im-c-map-styles__group'>
|
|
38
|
+
<h3 className='im-c-map-styles__heading' id='map-text-sizes'>Map size</h3>
|
|
39
|
+
<div className='im-c-map-styles__inner'>
|
|
40
|
+
{['small', 'medium', 'large'].map(size => (
|
|
41
|
+
<div className='im-c-map-styles__item' key={size}>
|
|
42
|
+
<button className='im-c-map-styles__button' onClick={() => handleMapSizeClick(size)} aria-pressed={size === currentMapSize}>
|
|
43
|
+
<div className='im-c-map-styles__image'>
|
|
44
|
+
<svg width='60' height='60' viewBox='0 0 60 60' fillRule='evenodd'>
|
|
45
|
+
<rect className='im-c-map-styles__image-bg' width='100%' height='100%' />
|
|
46
|
+
<g style={{ transform: `scale(${scaleFactor[size]})`, transformOrigin: '8px 52px' }}>
|
|
47
47
|
<path d={textSizeSvgPath} />
|
|
48
48
|
</g>
|
|
49
49
|
</svg>
|
|
@@ -57,4 +57,4 @@ export const MapStyles = ({ mapState, pluginConfig, services, mapProvider }) =>
|
|
|
57
57
|
)}
|
|
58
58
|
</div>
|
|
59
59
|
)
|
|
60
|
-
}
|
|
60
|
+
}
|
|
@@ -23,12 +23,12 @@ export function ScaleBar ({
|
|
|
23
23
|
}, [resolution, mapSize, pluginConfig.units])
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
|
-
<div className=
|
|
27
|
-
<span className=
|
|
28
|
-
<span className=
|
|
26
|
+
<div className='im-c-scale-bar' ref={elRef} style={{ width: `${scale.width}px` }}>
|
|
27
|
+
<span className='im-c-scale-bar__label'>
|
|
28
|
+
<span className='im-u-visually-hidden'>Scale bar: </span>
|
|
29
29
|
{scale.label}
|
|
30
|
-
<span aria-hidden=
|
|
31
|
-
<span className=
|
|
30
|
+
<span aria-hidden='true'>{scale.abbr}</span>
|
|
31
|
+
<span className='im-u-visually-hidden'>{scale.unit}</span>
|
|
32
32
|
</span>
|
|
33
33
|
</div>
|
|
34
34
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { errorMessages } from './defaults.js'
|
|
2
2
|
|
|
3
|
-
export function attachEvents({ appState, pluginState, mapProvider, useLocationButton }) {
|
|
3
|
+
export function attachEvents ({ appState, pluginState, mapProvider, useLocationButton }) {
|
|
4
4
|
const { dispatch: appDispatch, buttonRefs } = appState
|
|
5
5
|
const { dispatch: pluginDispatch } = pluginState
|
|
6
6
|
|
|
@@ -30,7 +30,7 @@ export function attachEvents({ appState, pluginState, mapProvider, useLocationBu
|
|
|
30
30
|
const message = getFriendlyError(err)
|
|
31
31
|
const triggeringElement = buttonRefs.current[useLocationButton.id]
|
|
32
32
|
pluginDispatch({ type: 'SET_ERROR_MESSAGE', payload: message })
|
|
33
|
-
appDispatch({ type: 'OPEN_PANEL', payload: { panelId: 'useLocation', props: { triggeringElement }}})
|
|
33
|
+
appDispatch({ type: 'OPEN_PANEL', payload: { panelId: 'useLocation', props: { triggeringElement } } })
|
|
34
34
|
}, {
|
|
35
35
|
enableHighAccuracy: true,
|
|
36
36
|
maximumAge: 0,
|
|
@@ -78,4 +78,4 @@ export function attachEvents({ appState, pluginState, mapProvider, useLocationBu
|
|
|
78
78
|
|
|
79
79
|
// Return helpers in case you want them in future
|
|
80
80
|
return { startTracking, stopTracking }
|
|
81
|
-
}
|
|
81
|
+
}
|
|
@@ -24,7 +24,7 @@ export const InteractInit = ({
|
|
|
24
24
|
mapState,
|
|
25
25
|
pluginState,
|
|
26
26
|
services,
|
|
27
|
-
mapProvider
|
|
27
|
+
mapProvider
|
|
28
28
|
})
|
|
29
29
|
|
|
30
30
|
// Refs updated synchronously each render — keeps callbacks fresh without re-attaching events
|
|
@@ -89,6 +89,5 @@ export const InteractInit = ({
|
|
|
89
89
|
return cleanupEvents
|
|
90
90
|
}, [pluginState.enabled, buttonConfig, events, eventBus, closeApp])
|
|
91
91
|
|
|
92
|
-
|
|
93
92
|
return null
|
|
94
93
|
}
|
|
@@ -7,9 +7,12 @@
|
|
|
7
7
|
import { DEFAULTS } from '../defaults.js'
|
|
8
8
|
|
|
9
9
|
export const enable = ({ pluginState, pluginConfig }, options) => {
|
|
10
|
-
pluginState.dispatch({
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
pluginState.dispatch({
|
|
11
|
+
type: 'ENABLE',
|
|
12
|
+
payload: {
|
|
13
|
+
...DEFAULTS,
|
|
14
|
+
...pluginConfig,
|
|
15
|
+
...options
|
|
16
|
+
}
|
|
17
|
+
})
|
|
15
18
|
}
|
|
@@ -18,9 +18,9 @@ describe('enable', () => {
|
|
|
18
18
|
expect(dispatch).toHaveBeenCalledWith({
|
|
19
19
|
type: 'ENABLE',
|
|
20
20
|
payload: expect.objectContaining({
|
|
21
|
-
interactionMode: 'select',
|
|
21
|
+
interactionMode: 'select', // options override DEFAULTS
|
|
22
22
|
multiSelect: DEFAULTS.multiSelect, // default preserved
|
|
23
|
-
markerColor: 'green',
|
|
23
|
+
markerColor: 'green', // options override pluginConfig
|
|
24
24
|
dataLayers: [{ layerId: 'test' }] // options passed
|
|
25
25
|
})
|
|
26
26
|
})
|
|
@@ -18,7 +18,7 @@ describe('attachEvents', () => {
|
|
|
18
18
|
getPluginState: () => pluginState,
|
|
19
19
|
mapState: {
|
|
20
20
|
markers: { remove: jest.fn(), getMarker: jest.fn(() => null) },
|
|
21
|
-
crossHair: { getDetail: jest.fn(() => ({ point: { x: 0, y: 0 }, coords: [0,0] })) }
|
|
21
|
+
crossHair: { getDetail: jest.fn(() => ({ point: { x: 0, y: 0 }, coords: [0, 0] })) }
|
|
22
22
|
},
|
|
23
23
|
buttonConfig: { selectDone: {}, selectAtTarget: {}, selectCancel: {} },
|
|
24
24
|
events: { MAP_CLICK: 'map:click' },
|
|
@@ -78,10 +78,10 @@ describe('attachEvents', () => {
|
|
|
78
78
|
params.clickReadyRef.current = true
|
|
79
79
|
cleanup = attachEvents(params)
|
|
80
80
|
|
|
81
|
-
const handler = params.eventBus.on.mock.calls.find(c => c[0]==='map:click')[1]
|
|
82
|
-
handler({ point:{x:1,y:2}, coords:[3,4] })
|
|
81
|
+
const handler = params.eventBus.on.mock.calls.find(c => c[0] === 'map:click')[1]
|
|
82
|
+
handler({ point: { x: 1, y: 2 }, coords: [3, 4] })
|
|
83
83
|
|
|
84
|
-
expect(params.handleInteraction).toHaveBeenCalledWith({ point:{x:1,y:2}, coords:[3,4] })
|
|
84
|
+
expect(params.handleInteraction).toHaveBeenCalledWith({ point: { x: 1, y: 2 }, coords: [3, 4] })
|
|
85
85
|
})
|
|
86
86
|
|
|
87
87
|
it('map click is suppressed when clickReadyRef is false', () => {
|
|
@@ -89,8 +89,8 @@ describe('attachEvents', () => {
|
|
|
89
89
|
params.clickReadyRef.current = false
|
|
90
90
|
cleanup = attachEvents(params)
|
|
91
91
|
|
|
92
|
-
const handler = params.eventBus.on.mock.calls.find(c => c[0]==='map:click')[1]
|
|
93
|
-
handler({ point:{x:1,y:2}, coords:[3,4] })
|
|
92
|
+
const handler = params.eventBus.on.mock.calls.find(c => c[0] === 'map:click')[1]
|
|
93
|
+
handler({ point: { x: 1, y: 2 }, coords: [3, 4] })
|
|
94
94
|
|
|
95
95
|
expect(params.handleInteraction).not.toHaveBeenCalled()
|
|
96
96
|
})
|
|
@@ -99,7 +99,7 @@ describe('attachEvents', () => {
|
|
|
99
99
|
const params = createParams()
|
|
100
100
|
cleanup = attachEvents(params)
|
|
101
101
|
|
|
102
|
-
const crossDetail = { point:{x:1,y:2}, coords:[3,4] }
|
|
102
|
+
const crossDetail = { point: { x: 1, y: 2 }, coords: [3, 4] }
|
|
103
103
|
params.mapState.crossHair.getDetail.mockReturnValue(crossDetail)
|
|
104
104
|
|
|
105
105
|
params.buttonConfig.selectAtTarget.onClick()
|
|
@@ -111,14 +111,14 @@ describe('attachEvents', () => {
|
|
|
111
111
|
cleanup = attachEvents(params)
|
|
112
112
|
|
|
113
113
|
// closeOnAction = true (already covered)
|
|
114
|
-
params.mapState.markers.getMarker.mockReturnValue({ coords:[1,2] })
|
|
114
|
+
params.mapState.markers.getMarker.mockReturnValue({ coords: [1, 2] })
|
|
115
115
|
params.buttonConfig.selectDone.onClick()
|
|
116
116
|
expect(params.closeApp).toHaveBeenCalled()
|
|
117
117
|
|
|
118
118
|
// cover closeOnAction = false
|
|
119
119
|
params.closeApp.mockClear()
|
|
120
120
|
params.pluginState.closeOnAction = false
|
|
121
|
-
params.mapState.markers.getMarker.mockReturnValue({ coords:[3,4] })
|
|
121
|
+
params.mapState.markers.getMarker.mockReturnValue({ coords: [3, 4] })
|
|
122
122
|
params.buttonConfig.selectDone.onClick()
|
|
123
123
|
expect(params.closeApp).not.toHaveBeenCalled()
|
|
124
124
|
})
|
|
@@ -155,11 +155,11 @@ describe('attachEvents', () => {
|
|
|
155
155
|
const params = createParams()
|
|
156
156
|
cleanup = attachEvents(params)
|
|
157
157
|
|
|
158
|
-
const selectHandler = params.eventBus.on.mock.calls.find(c => c[0]==='interact:selectFeature')[1]
|
|
159
|
-
const unselectHandler = params.eventBus.on.mock.calls.find(c => c[0]==='interact:unselectFeature')[1]
|
|
158
|
+
const selectHandler = params.eventBus.on.mock.calls.find(c => c[0] === 'interact:selectFeature')[1]
|
|
159
|
+
const unselectHandler = params.eventBus.on.mock.calls.find(c => c[0] === 'interact:unselectFeature')[1]
|
|
160
160
|
|
|
161
|
-
selectHandler({ featureId:'F1' })
|
|
162
|
-
unselectHandler({ featureId:'F2' })
|
|
161
|
+
selectHandler({ featureId: 'F1' })
|
|
162
|
+
unselectHandler({ featureId: 'F2' })
|
|
163
163
|
|
|
164
164
|
expect(params.pluginState.dispatch).toHaveBeenCalledTimes(2)
|
|
165
165
|
expect(params.mapState.markers.remove).toHaveBeenCalledTimes(2)
|
|
@@ -178,7 +178,7 @@ describe('attachEvents', () => {
|
|
|
178
178
|
|
|
179
179
|
// Ensure marker returns null (no coords)
|
|
180
180
|
params.mapState.markers.getMarker.mockReturnValue(null)
|
|
181
|
-
|
|
181
|
+
|
|
182
182
|
// Set up features and bounds
|
|
183
183
|
params.pluginState.selectedFeatures = [{ id: 'f1' }]
|
|
184
184
|
params.pluginState.selectionBounds = { sw: [0, 0], ne: [1, 1] }
|
|
@@ -194,7 +194,7 @@ describe('attachEvents', () => {
|
|
|
194
194
|
it('respects default closeOnAction when value is undefined (fallback to true)', () => {
|
|
195
195
|
const params = createParams()
|
|
196
196
|
// Explicitly set to undefined to trigger the ?? fallback
|
|
197
|
-
params.pluginState.closeOnAction = undefined
|
|
197
|
+
params.pluginState.closeOnAction = undefined
|
|
198
198
|
cleanup = attachEvents(params)
|
|
199
199
|
|
|
200
200
|
// Test for selectDone
|
|
@@ -34,7 +34,7 @@ export const useInteractionHandlers = ({
|
|
|
34
34
|
mapState,
|
|
35
35
|
pluginState,
|
|
36
36
|
services,
|
|
37
|
-
mapProvider
|
|
37
|
+
mapProvider
|
|
38
38
|
}) => {
|
|
39
39
|
const { markers } = mapState
|
|
40
40
|
const { dispatch, dataLayers, interactionMode, multiSelect, contiguous, markerColor, tolerance, selectedFeatures, selectionBounds, deselectOnClickOutside } = pluginState
|
|
@@ -71,7 +71,7 @@ export const useInteractionHandlers = ({
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
// Internal helper to keep complexity low
|
|
74
|
-
function processFeatureMatch({ feature, config }) {
|
|
74
|
+
function processFeatureMatch ({ feature, config }) {
|
|
75
75
|
markers.remove('location')
|
|
76
76
|
const isNewContiguous = contiguous && isContiguousWithAny(feature, selectedFeatures)
|
|
77
77
|
const featureId = feature.properties?.[config.idProperty] ?? feature.id
|
|
@@ -295,7 +295,7 @@ it('emits selectionchange once when bounds exist', () => {
|
|
|
295
295
|
|
|
296
296
|
it('skips emission when selection remains empty after being cleared', () => {
|
|
297
297
|
const eventBus = { emit: jest.fn() }
|
|
298
|
-
|
|
298
|
+
|
|
299
299
|
// 1. First render with a feature (prev is null, emission happens)
|
|
300
300
|
const { rerender } = renderHook(
|
|
301
301
|
({ features }) => useInteractionHandlers({
|
|
@@ -306,7 +306,7 @@ it('skips emission when selection remains empty after being cleared', () => {
|
|
|
306
306
|
}),
|
|
307
307
|
{ initialProps: { features: [{ id: 'f1' }] } }
|
|
308
308
|
)
|
|
309
|
-
|
|
309
|
+
|
|
310
310
|
expect(eventBus.emit).toHaveBeenCalledTimes(1)
|
|
311
311
|
eventBus.emit.mockClear()
|
|
312
312
|
|
|
@@ -315,11 +315,11 @@ it('skips emission when selection remains empty after being cleared', () => {
|
|
|
315
315
|
expect(eventBus.emit).toHaveBeenCalledTimes(1)
|
|
316
316
|
eventBus.emit.mockClear()
|
|
317
317
|
|
|
318
|
-
// 3. Rerender with empty selection AGAIN
|
|
318
|
+
// 3. Rerender with empty selection AGAIN
|
|
319
319
|
// This triggers: prev !== null AND prev.length === 0
|
|
320
320
|
rerender({ features: [] })
|
|
321
|
-
|
|
322
|
-
// Should skip emission because wasEmpty is true (via prev.length === 0)
|
|
321
|
+
|
|
322
|
+
// Should skip emission because wasEmpty is true (via prev.length === 0)
|
|
323
323
|
// and current features.length is 0
|
|
324
324
|
expect(eventBus.emit).not.toHaveBeenCalled()
|
|
325
325
|
})
|