@defra/interactive-map 0.0.37-alpha → 0.0.38-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/templates/draw-tools.njk +4 -3
- 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 +32 -0
- package/docs/examples/draw-tools.mdx +0 -4
- package/docs/plugins/draw.md +482 -0
- package/docs/plugins.md +2 -6
- package/govuk-prototype-kit.config.json +3 -2
- package/package.json +2 -4
- 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/css/index.css +1 -97
- package/plugins/datasets/dist/esm/im-datasets-plugin.js +1 -1
- package/plugins/datasets/dist/umd/im-datasets-plugin.js +1 -1
- package/plugins/draw/dist/esm/im-draw-ml-adapter.js +1 -0
- package/plugins/draw/dist/esm/im-draw-ol-adapter.js +1 -0
- package/plugins/draw/dist/esm/im-draw-plugin.js +1 -0
- package/plugins/draw/dist/esm/index.js +1 -0
- package/plugins/draw/dist/umd/im-draw-ml-adapter.js +1 -0
- package/plugins/draw/dist/umd/im-draw-ol-adapter.js +2 -0
- package/plugins/draw/dist/umd/im-draw-ol-adapter.js.LICENSE.txt +1 -0
- package/plugins/draw/dist/umd/im-draw-plugin.js +2 -0
- package/plugins/draw/dist/umd/im-draw-plugin.js.LICENSE.txt +1 -0
- package/plugins/draw/dist/umd/index.js +2 -0
- package/plugins/draw/dist/umd/index.js.LICENSE.txt +1 -0
- package/plugins/draw/src/DrawInit.jsx +89 -0
- package/plugins/draw/src/DrawInit.test.jsx +184 -0
- package/plugins/draw/src/adapterEvents.js +127 -0
- package/plugins/draw/src/adapterEvents.test.js +20 -0
- package/plugins/draw/src/adapters/adapterContract.test.js +48 -0
- package/plugins/draw/src/adapters/loadDrawAdapter.js +14 -0
- package/plugins/draw/src/adapters/loadDrawAdapter.test.js +53 -0
- package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.js +367 -0
- package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.test.js +799 -0
- package/plugins/draw/src/adapters/maplibre/defaults.js +1 -0
- package/plugins/draw/src/adapters/maplibre/drawEvents.js +35 -0
- package/plugins/draw/src/adapters/maplibre/mapboxDraw.js +126 -0
- package/plugins/draw/src/adapters/maplibre/mapboxDraw.test.js +268 -0
- package/plugins/draw/src/adapters/maplibre/mapboxSnap.js +39 -0
- package/plugins/draw/src/adapters/maplibre/mapboxSnap.test.js +91 -0
- package/plugins/draw/src/adapters/maplibre/modes/createDrawMode.js +58 -0
- package/plugins/draw/src/adapters/maplibre/modes/createDrawMode.test.js +53 -0
- package/plugins/draw/src/adapters/maplibre/modes/disabledMode.js +23 -0
- package/plugins/draw/src/adapters/maplibre/modes/disabledMode.test.js +21 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawLineMode.js +15 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawLineMode.test.js +37 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/__helpers__/harness.js +115 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/clickHandlers.js +193 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/clickHandlers.test.js +241 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/keyboardHandlers.js +78 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/keyboardHandlers.test.js +75 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.js +78 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.test.js +48 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/pointerHandlers.js +103 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/pointerHandlers.test.js +127 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/renderHelpers.js +59 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/renderHelpers.test.js +34 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/undoHandlers.js +193 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/undoHandlers.test.js +195 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawPolygonMode.js +16 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawPolygonMode.test.js +27 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/__helpers__/harness.js +107 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/geometryHelpers.js +139 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/geometryHelpers.test.js +46 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/helpers.js +2 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/helpers.test.js +17 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.js +151 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.test.js +123 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/pointerHandlers.js +161 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/pointerHandlers.test.js +98 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.js +133 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.test.js +105 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.js +166 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.test.js +133 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.js +210 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.test.js +167 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexQueries.js +121 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexQueries.test.js +73 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.js +249 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.test.js +153 -0
- package/plugins/draw/src/adapters/maplibre/snap/constants.js +2 -0
- package/plugins/draw/src/adapters/maplibre/snap/mapHandlers.js +39 -0
- package/plugins/draw/src/adapters/maplibre/snap/mapHandlers.test.js +106 -0
- package/plugins/draw/src/adapters/maplibre/snap/prototypePatches.js +148 -0
- package/plugins/draw/src/adapters/maplibre/snap/prototypePatches.test.js +238 -0
- package/plugins/draw/src/adapters/maplibre/snap/snapInstance.js +115 -0
- package/plugins/draw/src/adapters/maplibre/snap/snapInstance.test.js +151 -0
- package/plugins/draw/src/adapters/maplibre/snap/sourceData.js +34 -0
- package/plugins/draw/src/adapters/maplibre/snap/sourceData.test.js +62 -0
- package/plugins/draw/src/adapters/maplibre/styles.js +207 -0
- package/plugins/draw/src/adapters/maplibre/styles.test.js +155 -0
- package/plugins/draw/src/adapters/maplibre/utils/snapHelpers.js +202 -0
- package/plugins/draw/src/adapters/maplibre/utils/snapHelpers.test.js +253 -0
- package/plugins/draw/src/adapters/maplibre/utils/touchClickWorkaround.js +57 -0
- package/plugins/draw/src/adapters/maplibre/utils/touchClickWorkaround.test.js +106 -0
- package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.js +117 -0
- package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.test.js +159 -0
- package/plugins/draw/src/adapters/openlayers/__helpers__/harness.js +90 -0
- package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.js +178 -0
- package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.test.js +153 -0
- package/plugins/draw/src/adapters/openlayers/core/featureStore.js +69 -0
- package/plugins/draw/src/adapters/openlayers/core/featureStore.test.js +58 -0
- package/plugins/draw/src/adapters/openlayers/core/internalEvents.js +8 -0
- package/plugins/draw/src/adapters/openlayers/core/styles.js +155 -0
- package/plugins/draw/src/adapters/openlayers/core/styles.test.js +143 -0
- package/plugins/draw/src/adapters/openlayers/defaults.js +1 -0
- package/plugins/draw/src/adapters/openlayers/draw/DrawMode.js +272 -0
- package/plugins/draw/src/adapters/openlayers/draw/DrawMode.test.js +431 -0
- package/plugins/draw/src/adapters/openlayers/draw/drawInput.js +139 -0
- package/plugins/draw/src/adapters/openlayers/draw/drawInput.test.js +140 -0
- package/plugins/draw/src/adapters/openlayers/draw/vertexPlacement.js +144 -0
- package/plugins/draw/src/adapters/openlayers/draw/vertexPlacement.test.js +196 -0
- package/plugins/draw/src/adapters/openlayers/edit/EditMode.js +385 -0
- package/plugins/draw/src/adapters/openlayers/edit/EditMode.test.js +303 -0
- package/plugins/draw/src/adapters/openlayers/edit/activeVertexLayer.js +55 -0
- package/plugins/draw/src/adapters/openlayers/edit/activeVertexLayer.test.js +53 -0
- package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.js +157 -0
- package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.test.js +195 -0
- package/plugins/draw/src/adapters/openlayers/edit/midpointLayer.js +57 -0
- package/plugins/draw/src/adapters/openlayers/edit/midpointLayer.test.js +42 -0
- package/plugins/draw/src/adapters/openlayers/edit/modifyInteraction.js +83 -0
- package/plugins/draw/src/adapters/openlayers/edit/modifyInteraction.test.js +80 -0
- package/plugins/draw/src/adapters/openlayers/edit/nudge.js +118 -0
- package/plugins/draw/src/adapters/openlayers/edit/nudge.test.js +165 -0
- package/plugins/draw/src/adapters/openlayers/edit/pointerHandlers.js +79 -0
- package/plugins/draw/src/adapters/openlayers/edit/pointerHandlers.test.js +78 -0
- package/plugins/draw/src/adapters/openlayers/edit/selectionState.js +116 -0
- package/plugins/draw/src/adapters/openlayers/edit/selectionState.test.js +109 -0
- package/plugins/draw/src/adapters/openlayers/edit/touchHandler.js +184 -0
- package/plugins/draw/src/adapters/openlayers/edit/touchHandler.test.js +133 -0
- package/plugins/draw/src/adapters/openlayers/edit/undoOps.js +94 -0
- package/plugins/draw/src/adapters/openlayers/edit/undoOps.test.js +64 -0
- package/plugins/draw/src/adapters/openlayers/edit/vertexHitTest.js +74 -0
- package/plugins/draw/src/adapters/openlayers/edit/vertexHitTest.test.js +28 -0
- package/plugins/draw/src/adapters/openlayers/edit/vertexLayer.js +49 -0
- package/plugins/draw/src/adapters/openlayers/edit/vertexLayer.test.js +42 -0
- package/plugins/draw/src/adapters/openlayers/edit/vertexOps.js +100 -0
- package/plugins/draw/src/adapters/openlayers/edit/vertexOps.test.js +80 -0
- package/plugins/draw/src/adapters/openlayers/olDraw.js +40 -0
- package/plugins/draw/src/adapters/openlayers/olDraw.test.js +70 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapEngine.js +220 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapEngine.test.js +232 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapGeometry.js +198 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapGeometry.test.js +136 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapIndicator.js +81 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapIndicator.test.js +72 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapInteraction.js +57 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapInteraction.test.js +68 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapManager.js +99 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapManager.test.js +101 -0
- package/plugins/draw/src/adapters/openlayers/utils/geometryHelpers.js +103 -0
- package/plugins/draw/src/adapters/openlayers/utils/geometryHelpers.test.js +76 -0
- package/plugins/draw/src/adapters/openlayers/utils/olCoords.js +35 -0
- package/plugins/draw/src/adapters/openlayers/utils/olCoords.test.js +22 -0
- package/plugins/draw/src/adapters/openlayers/utils/sketchHelpers.js +22 -0
- package/plugins/draw/src/adapters/openlayers/utils/sketchHelpers.test.js +18 -0
- package/plugins/draw/src/adapters/openlayers/utils/touchTarget.js +8 -0
- package/plugins/draw/src/api/addFeature.js +22 -0
- package/plugins/draw/src/api/addFeature.test.js +41 -0
- package/plugins/draw/src/api/deleteFeature.js +11 -0
- package/plugins/draw/src/api/deleteFeature.test.js +24 -0
- package/plugins/draw/src/api/editFeature.js +54 -0
- package/plugins/draw/src/api/editFeature.test.js +134 -0
- package/plugins/draw/src/api/merge.js +30 -0
- package/plugins/draw/src/api/merge.test.js +57 -0
- package/plugins/draw/src/api/newLine.js +41 -0
- package/plugins/draw/src/api/newLine.test.js +93 -0
- package/plugins/draw/src/api/newPolygon.js +41 -0
- package/plugins/draw/src/api/newPolygon.test.js +93 -0
- package/plugins/draw/src/api/split.js +117 -0
- package/plugins/draw/src/api/split.test.js +204 -0
- package/plugins/draw/src/defaults.js +52 -0
- package/plugins/draw/src/defaults.test.js +18 -0
- package/plugins/draw/src/draw.scss +43 -0
- package/plugins/draw/src/events.js +237 -0
- package/plugins/draw/src/events.test.js +369 -0
- package/plugins/draw/src/index.js +10 -0
- package/plugins/draw/src/index.test.js +24 -0
- package/plugins/draw/src/manifest.js +170 -0
- package/plugins/draw/src/manifest.test.js +147 -0
- package/plugins/draw/src/reducer.js +69 -0
- package/plugins/draw/src/reducer.test.js +85 -0
- package/plugins/draw/src/utils/debounce.js +16 -0
- package/plugins/draw/src/utils/debounce.test.js +40 -0
- package/plugins/draw/src/utils/eventBus.js +36 -0
- package/plugins/draw/src/utils/eventBus.test.js +47 -0
- package/plugins/draw/src/utils/flattenStyleProperties.js +25 -0
- package/plugins/draw/src/utils/flattenStyleProperties.test.js +33 -0
- package/plugins/draw/src/utils/getValueForStyle.js +33 -0
- package/plugins/draw/src/utils/getValueForStyle.test.js +32 -0
- package/plugins/draw/src/utils/resolveColors.js +39 -0
- package/plugins/draw/src/utils/resolveColors.test.js +34 -0
- package/plugins/draw/src/utils/spatial.js +243 -0
- package/plugins/draw/src/utils/spatial.test.js +243 -0
- package/plugins/draw/src/utils/touchTarget.js +95 -0
- package/plugins/draw/src/utils/touchTarget.test.js +107 -0
- package/plugins/draw/src/utils/undoStack.js +31 -0
- package/plugins/draw/src/utils/undoStack.test.js +49 -0
- package/plugins/draw/src/validation/liveDrawChecks.js +120 -0
- package/plugins/draw/src/validation/liveDrawChecks.test.js +159 -0
- package/plugins/draw/src/validation/liveStroke.js +85 -0
- package/plugins/draw/src/validation/liveStroke.test.js +150 -0
- package/plugins/draw/src/validation/rules.areaError.test.js +12 -0
- package/plugins/draw/src/validation/rules.js +186 -0
- package/plugins/draw/src/validation/rules.test.js +120 -0
- package/plugins/draw/src/validation/validateGeometry.js +119 -0
- package/plugins/draw/src/validation/validateGeometry.test.js +200 -0
- 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/src/hooks/useInteractionHandlers.js +1 -1
- package/plugins/interact/src/hooks/useInteractionHandlers.test.js +1 -1
- package/plugins/interact/src/utils/buildStylesMap.js +1 -0
- package/plugins/search/dist/css/index.css +1 -317
- package/rollup.esm.mjs +35 -28
- package/sonar-project.properties +2 -2
- package/src/App/components/Attributions/Attributions.module.scss +1 -0
- package/src/App/components/Hints/Hints.module.scss +5 -4
- package/src/App/components/KeyboardHelp/KeyboardHelp.jsx +1 -1
- package/src/App/components/KeyboardHelp/KeyboardHelp.test.jsx +11 -0
- package/src/App/components/MoveControl/MoveControl.jsx +73 -9
- package/src/App/components/MoveControl/MoveControl.module.scss +12 -2
- package/src/App/components/MoveControl/MoveControl.test.jsx +136 -0
- package/src/App/hooks/useHintsAPI.js +67 -0
- package/src/App/hooks/useHintsAPI.test.js +145 -0
- package/src/App/renderer/PluginInits.jsx +4 -0
- package/src/App/renderer/PluginInits.test.jsx +7 -1
- package/src/InteractiveMap/InteractiveMap.js +20 -0
- package/src/InteractiveMap/InteractiveMap.test.js +7 -0
- package/src/config/events.js +4 -0
- package/src/scss/settings/_dimensions.scss +3 -0
- package/src/services/announcer.js +38 -3
- package/src/services/announcer.test.js +133 -1
- package/src/services/hints.js +3 -0
- package/src/services/hints.test.js +19 -0
- package/src/types.js +12 -0
- package/src/utils/detectInterfaceType.js +5 -1
- package/src/utils/isMac.js +15 -0
- package/src/utils/isMac.test.js +37 -0
- package/webpack.umd.mjs +1 -0
|
@@ -0,0 +1,799 @@
|
|
|
1
|
+
import { createMapboxDraw } from './mapboxDraw.js'
|
|
2
|
+
import { getSnapInstance, clearSnapState, clearSnapIndicator } from './utils/snapHelpers.js'
|
|
3
|
+
import { createEventBus } from '../../utils/eventBus.js'
|
|
4
|
+
import { MAPBOX_DRAW_EVENTS, CUSTOM_DRAW_EVENTS, STYLE_DATA_EVENT } from './drawEvents.js'
|
|
5
|
+
import { MaplibreDrawAdapter, displayedShape } from './MaplibreDrawAdapter.js'
|
|
6
|
+
|
|
7
|
+
jest.mock('./mapboxDraw.js', () => ({ createMapboxDraw: jest.fn() }))
|
|
8
|
+
jest.mock('./utils/snapHelpers.js', () => ({
|
|
9
|
+
getSnapInstance: jest.fn(),
|
|
10
|
+
clearSnapState: jest.fn(),
|
|
11
|
+
clearSnapIndicator: jest.fn()
|
|
12
|
+
}))
|
|
13
|
+
jest.mock('../../utils/eventBus.js', () => ({ createEventBus: jest.fn() }))
|
|
14
|
+
|
|
15
|
+
const SNAP_LAYER = 'snap-helper-circle'
|
|
16
|
+
|
|
17
|
+
const onHandler = (map, event) => map.on.mock.calls.find(([name]) => name === event)?.[1]
|
|
18
|
+
|
|
19
|
+
const setup = () => {
|
|
20
|
+
const map = {
|
|
21
|
+
on: jest.fn(),
|
|
22
|
+
off: jest.fn(),
|
|
23
|
+
fire: jest.fn(),
|
|
24
|
+
getLayer: jest.fn(() => null),
|
|
25
|
+
setLayoutProperty: jest.fn(),
|
|
26
|
+
getStyle: jest.fn(() => ({ layers: [] })),
|
|
27
|
+
moveLayer: jest.fn()
|
|
28
|
+
}
|
|
29
|
+
const undoStack = { clear: jest.fn() }
|
|
30
|
+
const mapProvider = { map, undoStack, snapEnabled: false }
|
|
31
|
+
const draw = {
|
|
32
|
+
changeMode: jest.fn(),
|
|
33
|
+
getMode: jest.fn(() => 'disabled'),
|
|
34
|
+
get: jest.fn((id) => ({ id })),
|
|
35
|
+
add: jest.fn(),
|
|
36
|
+
delete: jest.fn(),
|
|
37
|
+
deleteAll: jest.fn(),
|
|
38
|
+
trash: jest.fn(),
|
|
39
|
+
setFeatureProperty: jest.fn()
|
|
40
|
+
}
|
|
41
|
+
const removeDraw = jest.fn()
|
|
42
|
+
createMapboxDraw.mockReturnValue({ draw, remove: removeDraw })
|
|
43
|
+
|
|
44
|
+
const bus = { on: jest.fn(), off: jest.fn(), emit: jest.fn() }
|
|
45
|
+
createEventBus.mockReturnValue(bus)
|
|
46
|
+
|
|
47
|
+
const options = {
|
|
48
|
+
mapStyle: 'light',
|
|
49
|
+
events: { MAP_SET_STYLE: 'mss' },
|
|
50
|
+
eventBus: { on: jest.fn() },
|
|
51
|
+
snapLayers: ['layer-a']
|
|
52
|
+
}
|
|
53
|
+
const adapter = new MaplibreDrawAdapter(mapProvider, options)
|
|
54
|
+
|
|
55
|
+
return { adapter, map, mapProvider, draw, removeDraw, bus, undoStack, options }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
jest.clearAllMocks()
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
describe('construction', () => {
|
|
63
|
+
test('creates the MapboxDraw control with the provided options', () => {
|
|
64
|
+
const { options } = setup()
|
|
65
|
+
expect(createMapboxDraw).toHaveBeenCalledWith({
|
|
66
|
+
mapStyle: 'light',
|
|
67
|
+
mapProvider: expect.any(Object),
|
|
68
|
+
events: options.events,
|
|
69
|
+
eventBus: options.eventBus,
|
|
70
|
+
snapLayers: ['layer-a'],
|
|
71
|
+
pluginConfig: {}
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
test('forwards a provided pluginConfig through to createMapboxDraw', () => {
|
|
76
|
+
const map = {
|
|
77
|
+
on: jest.fn(),
|
|
78
|
+
off: jest.fn(),
|
|
79
|
+
fire: jest.fn(),
|
|
80
|
+
getLayer: jest.fn(() => null),
|
|
81
|
+
setLayoutProperty: jest.fn(),
|
|
82
|
+
getStyle: jest.fn(() => ({ layers: [] })),
|
|
83
|
+
moveLayer: jest.fn()
|
|
84
|
+
}
|
|
85
|
+
const mapProvider = { map, undoStack: { clear: jest.fn() }, snapEnabled: false }
|
|
86
|
+
createMapboxDraw.mockReturnValue({ draw: { changeMode: jest.fn(), getMode: jest.fn() }, remove: jest.fn() })
|
|
87
|
+
createEventBus.mockReturnValue({ on: jest.fn(), off: jest.fn(), emit: jest.fn() })
|
|
88
|
+
|
|
89
|
+
const pluginConfig = { shapeStroke: '#custom' }
|
|
90
|
+
// eslint-disable-next-line no-new
|
|
91
|
+
new MaplibreDrawAdapter(mapProvider, {
|
|
92
|
+
mapStyle: 'light',
|
|
93
|
+
events: { MAP_SET_STYLE: 'mss' },
|
|
94
|
+
eventBus: { on: jest.fn() },
|
|
95
|
+
snapLayers: ['layer-a'],
|
|
96
|
+
pluginConfig
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
expect(createMapboxDraw).toHaveBeenCalledWith(expect.objectContaining({ pluginConfig }))
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test('subscribes to every MapLibre draw event', () => {
|
|
103
|
+
const { map } = setup()
|
|
104
|
+
const subscribed = map.on.mock.calls.map(([name]) => name)
|
|
105
|
+
expect(subscribed).toEqual(expect.arrayContaining([
|
|
106
|
+
MAPBOX_DRAW_EVENTS.CREATE, MAPBOX_DRAW_EVENTS.UPDATE, MAPBOX_DRAW_EVENTS.MODE_CHANGE,
|
|
107
|
+
CUSTOM_DRAW_EVENTS.EDIT_FINISH, CUSTOM_DRAW_EVENTS.CANCEL, CUSTOM_DRAW_EVENTS.VERTEX_SELECTION,
|
|
108
|
+
CUSTOM_DRAW_EVENTS.VERTEX_CHANGE, CUSTOM_DRAW_EVENTS.UNDO_CHANGE, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE,
|
|
109
|
+
STYLE_DATA_EVENT
|
|
110
|
+
]))
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
describe('map event normalisation', () => {
|
|
115
|
+
test('create/editfinish/update forward the first feature', () => {
|
|
116
|
+
const { map, bus } = setup()
|
|
117
|
+
const feature = { id: 'f1' }
|
|
118
|
+
|
|
119
|
+
onHandler(map, MAPBOX_DRAW_EVENTS.CREATE)({ features: [feature] })
|
|
120
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.EDIT_FINISH)({ features: [feature] })
|
|
121
|
+
onHandler(map, MAPBOX_DRAW_EVENTS.UPDATE)({ features: [feature] })
|
|
122
|
+
|
|
123
|
+
expect(bus.emit).toHaveBeenCalledWith('create', feature)
|
|
124
|
+
expect(bus.emit).toHaveBeenCalledWith('editfinish', feature)
|
|
125
|
+
expect(bus.emit).toHaveBeenCalledWith('update', feature)
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
test('cancel forwards with no payload', () => {
|
|
129
|
+
const { map, bus } = setup()
|
|
130
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.CANCEL)()
|
|
131
|
+
expect(bus.emit).toHaveBeenCalledWith('cancel')
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
test('vertexselection/vertexchange normalise the numVertecies typo', () => {
|
|
135
|
+
const { map, bus } = setup()
|
|
136
|
+
|
|
137
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.VERTEX_SELECTION)({ numVertecies: 3, index: 1 })
|
|
138
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.VERTEX_CHANGE)({ numVertecies: 2 })
|
|
139
|
+
|
|
140
|
+
expect(bus.emit).toHaveBeenCalledWith('vertexselection', expect.objectContaining({ numVertices: 3, index: 1 }))
|
|
141
|
+
expect(bus.emit).toHaveBeenCalledWith('vertexchange', expect.objectContaining({ numVertices: 2 }))
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test('undochange forwards the stack length', () => {
|
|
145
|
+
const { map, bus } = setup()
|
|
146
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.UNDO_CHANGE)({ length: 4 })
|
|
147
|
+
expect(bus.emit).toHaveBeenCalledWith('undochange', 4)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
test('geometrychange forwards the raw event', () => {
|
|
151
|
+
const { map, bus } = setup()
|
|
152
|
+
const e = { type: 'Polygon' }
|
|
153
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)(e)
|
|
154
|
+
expect(bus.emit).toHaveBeenCalledWith('geometrychange', e)
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
test('placementblocked forwards the raw event', () => {
|
|
158
|
+
const { map, bus } = setup()
|
|
159
|
+
const e = { phase: 'place', reason: 'outside region' }
|
|
160
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.PLACEMENT_BLOCKED)(e)
|
|
161
|
+
expect(bus.emit).toHaveBeenCalledWith('placementblocked', e)
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
describe('displayedShape helper', () => {
|
|
166
|
+
test('builds a polygon feature from draw_polygon mode', () => {
|
|
167
|
+
const result = displayedShape('draw_polygon', [[[0, 0], [10, 0], [10, 10], [0, 0]]])
|
|
168
|
+
expect(result?.feature?.type).toBe('Feature')
|
|
169
|
+
expect(result?.feature?.geometry?.type).toBe('Polygon')
|
|
170
|
+
expect(result?.numVertices).toBe(3)
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test('builds a line feature from draw_line mode', () => {
|
|
174
|
+
const result = displayedShape('draw_line', [[0, 0], [10, 0], [10, 10]])
|
|
175
|
+
expect(result?.feature?.type).toBe('Feature')
|
|
176
|
+
expect(result?.feature?.geometry?.type).toBe('LineString')
|
|
177
|
+
expect(result?.numVertices).toBe(2)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
test('detects polygon vs line in edit_vertex mode from coordinate nesting', () => {
|
|
181
|
+
const polygon = displayedShape('edit_vertex', [[[0, 0], [10, 0], [10, 10], [0, 0]]])
|
|
182
|
+
expect(polygon?.feature?.geometry?.type).toBe('Polygon')
|
|
183
|
+
const line = displayedShape('edit_vertex', [[0, 0], [10, 0], [10, 10]])
|
|
184
|
+
expect(line?.feature?.geometry?.type).toBe('LineString')
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
test('returns null for an unknown mode', () => {
|
|
188
|
+
expect(displayedShape('unknown_mode', [[0, 0], [10, 0]])).toBeNull()
|
|
189
|
+
})
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
describe('live invalid stroke (draw mode)', () => {
|
|
193
|
+
// Displayed rings (placed vertices + cursor) as the listener really receives them:
|
|
194
|
+
// MapLibre's fire() wraps the gl-draw feature in an Event whose `type` is the
|
|
195
|
+
// event name — the geometry type is clobbered, only `coordinates` survives.
|
|
196
|
+
const bowtie = { type: 'draw.geometrychange', coordinates: [[[0, 0], [10, 10], [10, 0], [0, 10]]] }
|
|
197
|
+
const square = { type: 'draw.geometrychange', coordinates: [[[0, 0], [10, 0], [10, 10], [0, 10]]] }
|
|
198
|
+
|
|
199
|
+
const drawPolygonSetup = () => {
|
|
200
|
+
const fixture = setup()
|
|
201
|
+
fixture.draw.getMode.mockReturnValue('draw_polygon')
|
|
202
|
+
fixture.map.getLayer.mockReturnValue({})
|
|
203
|
+
return fixture
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
test('a self-intersecting displayed ring turns the stroke dashed; simple again restores it', () => {
|
|
207
|
+
const { map } = drawPolygonSetup()
|
|
208
|
+
const fire = onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)
|
|
209
|
+
|
|
210
|
+
fire(bowtie)
|
|
211
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'visible')
|
|
212
|
+
|
|
213
|
+
map.setLayoutProperty.mockClear()
|
|
214
|
+
fire(square)
|
|
215
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active.hot', 'visibility', 'visible')
|
|
216
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'none')
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
test('only restyles when the invalid state flips, not on every move', () => {
|
|
220
|
+
const { map } = drawPolygonSetup()
|
|
221
|
+
const fire = onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)
|
|
222
|
+
fire(bowtie)
|
|
223
|
+
const callsAfterFlip = map.setLayoutProperty.mock.calls.length
|
|
224
|
+
fire(bowtie)
|
|
225
|
+
fire(bowtie)
|
|
226
|
+
expect(map.setLayoutProperty.mock.calls.length).toBe(callsAfterFlip)
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
test('commit-level (has a phase) events do not drive the stroke; events.js owns those', () => {
|
|
230
|
+
const { map } = drawPolygonSetup()
|
|
231
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)({ feature: bowtie, phase: 'commit-add', vertexIndex: 3 })
|
|
232
|
+
expect(map.setLayoutProperty).not.toHaveBeenCalled()
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
test('lines never go dashed from the live check', () => {
|
|
236
|
+
const { map, draw } = drawPolygonSetup()
|
|
237
|
+
draw.getMode.mockReturnValue('draw_line')
|
|
238
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)({ type: 'draw.geometrychange', coordinates: [[0, 0], [10, 10], [10, 0], [0, 10]] })
|
|
239
|
+
expect(map.setLayoutProperty).not.toHaveBeenCalled()
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
test('the rubber band sitting on the just-placed vertex never reads as a crossing', () => {
|
|
243
|
+
const { map } = drawPolygonSetup()
|
|
244
|
+
// 3 placed + rubber band duplicating the last placed vertex.
|
|
245
|
+
const justPlaced = { type: 'draw.geometrychange', coordinates: [[[0, 0], [10, 0], [10, 10], [10, 10]]] }
|
|
246
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)(justPlaced)
|
|
247
|
+
expect(map.setLayoutProperty).not.toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'visible')
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
test('a placement-vetoing path disables Add point; a legal one re-enables it', () => {
|
|
251
|
+
const { map, bus } = drawPolygonSetup()
|
|
252
|
+
const fire = onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)
|
|
253
|
+
// Open drawn path crosses itself → placing at the crosshair would be vetoed.
|
|
254
|
+
fire({ type: 'draw.geometrychange', coordinates: [[[0, 0], [2, 2], [2, 0], [0, 2]]] })
|
|
255
|
+
expect(bus.emit).toHaveBeenCalledWith('canplacechange', expect.objectContaining({ canPlace: false, reason: expect.any(String) }))
|
|
256
|
+
fire({ type: 'draw.geometrychange', coordinates: [[[0, 0], [2, 0], [2, 2], [0, 2]]] })
|
|
257
|
+
expect(bus.emit).toHaveBeenCalledWith('canplacechange', expect.objectContaining({ canPlace: true }))
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
test('a red stroke via the closing edge alone keeps Add point enabled', () => {
|
|
261
|
+
const { map, bus } = drawPolygonSetup()
|
|
262
|
+
// Only the implicit closing edge crosses: stroke dashed, but the placement is legal.
|
|
263
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)({ type: 'draw.geometrychange', coordinates: [[[0, 0], [2, 0], [0, 2], [2, 2]]] })
|
|
264
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'visible')
|
|
265
|
+
expect(bus.emit).not.toHaveBeenCalledWith('canplacechange', expect.objectContaining({ canPlace: false }))
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
test('the user callback runs ONCE per frame in draw mode, with phase preview, driving both the stroke and Add point from that single call', () => {
|
|
269
|
+
jest.useFakeTimers()
|
|
270
|
+
const { map, bus } = drawPolygonSetup()
|
|
271
|
+
map._drawGeometryValidator = jest.fn(() => ({ valid: false, reason: 'outside region' }))
|
|
272
|
+
const fire = onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)
|
|
273
|
+
fire(square)
|
|
274
|
+
expect(map._drawGeometryValidator).not.toHaveBeenCalled() // deferred to the frame
|
|
275
|
+
jest.runAllTimers()
|
|
276
|
+
expect(map._drawGeometryValidator).toHaveBeenCalledTimes(1) // not once per gate
|
|
277
|
+
expect(map._drawGeometryValidator).toHaveBeenCalledWith(expect.objectContaining({ phase: 'preview' }))
|
|
278
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'visible')
|
|
279
|
+
expect(bus.emit).toHaveBeenCalledWith('canplacechange', expect.objectContaining({ canPlace: false, reason: 'outside region' }))
|
|
280
|
+
jest.useRealTimers()
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
test('the user callback runs even before any vertex is placed, gating both the stroke and Add point from the very first candidate point', () => {
|
|
284
|
+
jest.useFakeTimers()
|
|
285
|
+
const { map, bus } = drawPolygonSetup()
|
|
286
|
+
map._drawGeometryValidator = jest.fn(() => ({ valid: false, reason: 'outside region' }))
|
|
287
|
+
const fire = onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)
|
|
288
|
+
// Zero committed vertices — coordinates is just the rubber-band cursor point.
|
|
289
|
+
fire({ type: 'draw.geometrychange', coordinates: [[[5, 5]]] })
|
|
290
|
+
jest.runAllTimers()
|
|
291
|
+
expect(map._drawGeometryValidator).toHaveBeenCalledWith(expect.objectContaining({ numVertices: 0, phase: 'preview' }))
|
|
292
|
+
expect(bus.emit).toHaveBeenCalledWith('canplacechange', expect.objectContaining({ canPlace: false, reason: 'outside region' }))
|
|
293
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'visible')
|
|
294
|
+
jest.useRealTimers()
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
test('entering a draw mode resets the stroke to solid', () => {
|
|
298
|
+
const { adapter, map } = drawPolygonSetup()
|
|
299
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)(bowtie) // dashed
|
|
300
|
+
map.setLayoutProperty.mockClear()
|
|
301
|
+
adapter.changeMode('draw_polygon')
|
|
302
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active.hot', 'visibility', 'visible')
|
|
303
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'none')
|
|
304
|
+
// ...and the flip guard is reset with it, so the next crossing restyles again.
|
|
305
|
+
map.setLayoutProperty.mockClear()
|
|
306
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)(bowtie)
|
|
307
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'visible')
|
|
308
|
+
})
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
describe('live invalid stroke (edit mode)', () => {
|
|
312
|
+
const editSetup = () => {
|
|
313
|
+
const fixture = setup()
|
|
314
|
+
fixture.draw.getMode.mockReturnValue('edit_vertex')
|
|
315
|
+
fixture.map.getLayer.mockReturnValue({})
|
|
316
|
+
return fixture
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
test('dragging a polygon vertex into a crossing turns the stroke dashed, and back', () => {
|
|
320
|
+
const { map } = editSetup()
|
|
321
|
+
const fire = onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)
|
|
322
|
+
// Edit payloads have the type clobbered too — polygon detected from ring nesting.
|
|
323
|
+
fire({ type: 'draw.geometrychange', coordinates: [[[0, 0], [10, 10], [10, 0], [0, 10]]] })
|
|
324
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'visible')
|
|
325
|
+
map.setLayoutProperty.mockClear()
|
|
326
|
+
fire({ type: 'draw.geometrychange', coordinates: [[[0, 0], [10, 0], [10, 10], [0, 10]]] })
|
|
327
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active.hot', 'visibility', 'visible')
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
test('validity flips while editing also gate the Done button', () => {
|
|
331
|
+
const { map, bus } = editSetup()
|
|
332
|
+
const fire = onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)
|
|
333
|
+
fire({ type: 'draw.geometrychange', coordinates: [[[0, 0], [10, 10], [10, 0], [0, 10]]] })
|
|
334
|
+
expect(bus.emit).toHaveBeenCalledWith('validitychange', expect.objectContaining({ valid: false, reason: expect.any(String) }))
|
|
335
|
+
fire({ type: 'draw.geometrychange', coordinates: [[[0, 0], [10, 0], [10, 10], [0, 10]]] })
|
|
336
|
+
expect(bus.emit).toHaveBeenCalledWith('validitychange', expect.objectContaining({ valid: true }))
|
|
337
|
+
// Add point is a draw-mode concern — never driven from edit mode.
|
|
338
|
+
expect(bus.emit).not.toHaveBeenCalledWith('canplacechange', expect.anything())
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
test('lines never go dashed from the default rules while editing', () => {
|
|
342
|
+
const { map } = editSetup()
|
|
343
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)({ type: 'draw.geometrychange', coordinates: [[0, 0], [10, 10], [10, 0], [0, 10]] })
|
|
344
|
+
expect(map.setLayoutProperty).not.toHaveBeenCalled()
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
test('the user callback runs throttled during an edit drag', () => {
|
|
348
|
+
jest.useFakeTimers()
|
|
349
|
+
const { map } = editSetup()
|
|
350
|
+
map._drawGeometryValidator = jest.fn(() => ({ valid: false, reason: 'outside region' }))
|
|
351
|
+
const fire = onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)
|
|
352
|
+
fire({ type: 'draw.geometrychange', coordinates: [[[0, 0], [10, 0], [10, 10], [0, 10]]] })
|
|
353
|
+
fire({ type: 'draw.geometrychange', coordinates: [[[0, 0], [10, 0], [10, 10], [0, 11]]] })
|
|
354
|
+
expect(map._drawGeometryValidator).not.toHaveBeenCalled() // deferred to the frame
|
|
355
|
+
jest.runAllTimers()
|
|
356
|
+
expect(map._drawGeometryValidator).toHaveBeenCalledTimes(1) // trailing edge only
|
|
357
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'visible')
|
|
358
|
+
jest.useRealTimers()
|
|
359
|
+
})
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
describe('_geometryValidator accessor', () => {
|
|
363
|
+
test('stores the validator on the map for modes to read, and reads it back', () => {
|
|
364
|
+
const { adapter, map } = setup()
|
|
365
|
+
const validator = () => true
|
|
366
|
+
adapter._geometryValidator = validator
|
|
367
|
+
expect(map._drawGeometryValidator).toBe(validator)
|
|
368
|
+
expect(adapter._geometryValidator).toBe(validator)
|
|
369
|
+
})
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
describe('changeMode', () => {
|
|
373
|
+
test('records the editing feature id when entering edit_vertex', () => {
|
|
374
|
+
const { adapter, draw } = setup()
|
|
375
|
+
adapter.changeMode('edit_vertex', { featureId: 'f9' })
|
|
376
|
+
expect(draw.changeMode).toHaveBeenCalledWith('edit_vertex', { featureId: 'f9' })
|
|
377
|
+
})
|
|
378
|
+
|
|
379
|
+
test('defaults the editing feature id to null when omitted', () => {
|
|
380
|
+
const { adapter, draw } = setup()
|
|
381
|
+
adapter.changeMode('edit_vertex', {})
|
|
382
|
+
draw.getMode.mockReturnValue('edit_vertex')
|
|
383
|
+
adapter.done()
|
|
384
|
+
// no editing feature id → no editfinish fired
|
|
385
|
+
expect(draw.changeMode).toHaveBeenCalledWith('edit_vertex', {})
|
|
386
|
+
})
|
|
387
|
+
|
|
388
|
+
test('passes through non-edit modes with default options', () => {
|
|
389
|
+
const { adapter, draw } = setup()
|
|
390
|
+
adapter.changeMode('draw_polygon')
|
|
391
|
+
expect(draw.changeMode).toHaveBeenCalledWith('draw_polygon', {})
|
|
392
|
+
})
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
describe('setGeometryValid', () => {
|
|
396
|
+
test('records validity on the map for the draw mode to read', () => {
|
|
397
|
+
const { adapter, map } = setup()
|
|
398
|
+
adapter.setGeometryValid(false)
|
|
399
|
+
expect(map._drawGeometryValid).toBe(false)
|
|
400
|
+
adapter.setGeometryValid(true)
|
|
401
|
+
expect(map._drawGeometryValid).toBe(true)
|
|
402
|
+
})
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
describe('setInvalid', () => {
|
|
406
|
+
test('shows the dashed stroke and hides the solid stroke and fill when invalid', () => {
|
|
407
|
+
const { adapter, map } = setup()
|
|
408
|
+
map.getLayer.mockReturnValue({}) // every layer exists
|
|
409
|
+
adapter.setInvalid(true)
|
|
410
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active.hot', 'visibility', 'none')
|
|
411
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active.cold', 'visibility', 'none')
|
|
412
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'visible')
|
|
413
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.cold', 'visibility', 'visible')
|
|
414
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('fill-active.hot', 'visibility', 'none')
|
|
415
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('fill-active.cold', 'visibility', 'none')
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
test('restores the solid stroke and fill when valid again', () => {
|
|
419
|
+
const { adapter, map } = setup()
|
|
420
|
+
map.getLayer.mockReturnValue({})
|
|
421
|
+
adapter.setInvalid(true)
|
|
422
|
+
map.setLayoutProperty.mockClear()
|
|
423
|
+
adapter.setInvalid(false)
|
|
424
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active.hot', 'visibility', 'visible')
|
|
425
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'none')
|
|
426
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('fill-active.hot', 'visibility', 'visible')
|
|
427
|
+
})
|
|
428
|
+
|
|
429
|
+
test('writes are flip-guarded: repeating the same state does not touch the layers', () => {
|
|
430
|
+
const { adapter, map } = setup()
|
|
431
|
+
map.getLayer.mockReturnValue({})
|
|
432
|
+
adapter.setInvalid(false) // already solid — no-op
|
|
433
|
+
expect(map.setLayoutProperty).not.toHaveBeenCalled()
|
|
434
|
+
adapter.setInvalid(true)
|
|
435
|
+
map.setLayoutProperty.mockClear()
|
|
436
|
+
adapter.setInvalid(true) // already dashed — no-op
|
|
437
|
+
expect(map.setLayoutProperty).not.toHaveBeenCalled()
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
test('skips layers that are not present on the map', () => {
|
|
441
|
+
const { adapter, map } = setup()
|
|
442
|
+
map.getLayer.mockReturnValue(null)
|
|
443
|
+
adapter.setInvalid(true)
|
|
444
|
+
expect(map.setLayoutProperty).not.toHaveBeenCalled()
|
|
445
|
+
})
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
describe('simple delegations', () => {
|
|
449
|
+
test('getMode delegates to the draw control', () => {
|
|
450
|
+
const { adapter, draw } = setup()
|
|
451
|
+
draw.getMode.mockReturnValue('draw_line')
|
|
452
|
+
expect(adapter.getMode()).toBe('draw_line')
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
test('setInterfaceType fires the interface-type-change event', () => {
|
|
456
|
+
const { adapter, map } = setup()
|
|
457
|
+
adapter.setInterfaceType('keyboard')
|
|
458
|
+
expect(map.fire).toHaveBeenCalledWith(CUSTOM_DRAW_EVENTS.INTERFACE_TYPE_CHANGE, { interfaceType: 'keyboard' })
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
test('undo fires the undo event', () => {
|
|
462
|
+
const { adapter, map } = setup()
|
|
463
|
+
adapter.undo()
|
|
464
|
+
expect(map.fire).toHaveBeenCalledWith(CUSTOM_DRAW_EVENTS.UNDO)
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
test('nudgeSelectedVertex fires the nudge-vertex event with the given delta and step size', () => {
|
|
468
|
+
const { adapter, map } = setup()
|
|
469
|
+
adapter.nudgeSelectedVertex(1, 0, true)
|
|
470
|
+
expect(map.fire).toHaveBeenCalledWith(CUSTOM_DRAW_EVENTS.NUDGE_VERTEX, { dx: 1, dy: 0, isLargeStep: true })
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
test('deleteVertex is a no-op', () => {
|
|
474
|
+
const { adapter, draw, map } = setup()
|
|
475
|
+
expect(() => adapter.deleteVertex()).not.toThrow()
|
|
476
|
+
expect(draw.changeMode).not.toHaveBeenCalled()
|
|
477
|
+
expect(map.fire).not.toHaveBeenCalled()
|
|
478
|
+
})
|
|
479
|
+
|
|
480
|
+
test('feature store methods delegate to the draw control', () => {
|
|
481
|
+
const { adapter, draw } = setup()
|
|
482
|
+
adapter.get('a')
|
|
483
|
+
adapter.add({ id: 'b' })
|
|
484
|
+
adapter.delete('c')
|
|
485
|
+
adapter.deleteAll()
|
|
486
|
+
adapter.setFeatureProperty('d', 'p', 1)
|
|
487
|
+
|
|
488
|
+
expect(draw.get).toHaveBeenCalledWith('a')
|
|
489
|
+
expect(draw.add).toHaveBeenCalledWith({ id: 'b' })
|
|
490
|
+
expect(draw.delete).toHaveBeenCalledWith('c')
|
|
491
|
+
expect(draw.deleteAll).toHaveBeenCalled()
|
|
492
|
+
expect(draw.setFeatureProperty).toHaveBeenCalledWith('d', 'p', 1)
|
|
493
|
+
})
|
|
494
|
+
|
|
495
|
+
test('setDrawingPreviewProperty tags the in-progress feature and re-renders', () => {
|
|
496
|
+
const { adapter, map } = setup()
|
|
497
|
+
const render = jest.fn()
|
|
498
|
+
const drawEvent = { coordinates: [[0, 0], [1, 1]], properties: {}, ctx: { store: { render } } }
|
|
499
|
+
// Phase-less events are rubber-band moves — cached so setDrawingPreviewProperty
|
|
500
|
+
// has something to tag (the in-progress feature has no id yet to look up).
|
|
501
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)(drawEvent)
|
|
502
|
+
|
|
503
|
+
adapter.setDrawingPreviewProperty('splitter', 'valid')
|
|
504
|
+
|
|
505
|
+
expect(drawEvent.properties.splitter).toBe('valid')
|
|
506
|
+
expect(render).toHaveBeenCalled()
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
test('setDrawingPreviewProperty tolerates nothing having been drawn yet', () => {
|
|
510
|
+
const { adapter } = setup()
|
|
511
|
+
expect(() => adapter.setDrawingPreviewProperty('splitter', 'valid')).not.toThrow()
|
|
512
|
+
})
|
|
513
|
+
|
|
514
|
+
test('setDrawingPreviewProperty ignores commit-level (has a phase) events', () => {
|
|
515
|
+
const { adapter, map } = setup()
|
|
516
|
+
const render = jest.fn()
|
|
517
|
+
// A commit event (has a phase) must not become the cached preview target — it
|
|
518
|
+
// carries a `feature`, not the live `properties` object rubber-band moves do.
|
|
519
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)({ feature: {}, phase: 'commit-add', ctx: { store: { render } } })
|
|
520
|
+
|
|
521
|
+
expect(() => adapter.setDrawingPreviewProperty('splitter', 'valid')).not.toThrow()
|
|
522
|
+
expect(render).not.toHaveBeenCalled()
|
|
523
|
+
})
|
|
524
|
+
|
|
525
|
+
test('on/off delegate to the internal event bus', () => {
|
|
526
|
+
const { adapter, bus } = setup()
|
|
527
|
+
const handler = jest.fn()
|
|
528
|
+
adapter.on('create', handler)
|
|
529
|
+
adapter.off('create', handler)
|
|
530
|
+
expect(bus.on).toHaveBeenCalledWith('create', handler)
|
|
531
|
+
expect(bus.off).toHaveBeenCalledWith('create', handler)
|
|
532
|
+
})
|
|
533
|
+
|
|
534
|
+
test('isSnapEnabled reflects the provider flag', () => {
|
|
535
|
+
const { adapter, mapProvider } = setup()
|
|
536
|
+
expect(adapter.isSnapEnabled()).toBe(false)
|
|
537
|
+
mapProvider.snapEnabled = true
|
|
538
|
+
expect(adapter.isSnapEnabled()).toBe(true)
|
|
539
|
+
})
|
|
540
|
+
})
|
|
541
|
+
|
|
542
|
+
describe('done', () => {
|
|
543
|
+
test('clears the undo stack and fires editfinish when editing a vertex', () => {
|
|
544
|
+
const { adapter, map, draw, undoStack } = setup()
|
|
545
|
+
adapter.changeMode('edit_vertex', { featureId: 'f1' })
|
|
546
|
+
draw.getMode.mockReturnValue('edit_vertex')
|
|
547
|
+
|
|
548
|
+
adapter.done()
|
|
549
|
+
|
|
550
|
+
expect(undoStack.clear).toHaveBeenCalled()
|
|
551
|
+
expect(map.fire).toHaveBeenCalledWith(CUSTOM_DRAW_EVENTS.EDIT_FINISH, { features: [{ id: 'f1' }] })
|
|
552
|
+
expect(draw.changeMode).not.toHaveBeenCalledWith('disabled')
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
test('disables the control when finishing a draw mode', () => {
|
|
556
|
+
const { adapter, draw } = setup()
|
|
557
|
+
draw.getMode.mockReturnValue('draw_polygon')
|
|
558
|
+
adapter.done()
|
|
559
|
+
expect(draw.changeMode).toHaveBeenCalledWith('disabled')
|
|
560
|
+
|
|
561
|
+
draw.getMode.mockReturnValue('draw_line')
|
|
562
|
+
adapter.done()
|
|
563
|
+
expect(draw.changeMode).toHaveBeenCalledWith('disabled')
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
test('does nothing further for edit_vertex without an editing feature id', () => {
|
|
567
|
+
const { adapter, draw, map } = setup()
|
|
568
|
+
draw.getMode.mockReturnValue('edit_vertex')
|
|
569
|
+
adapter.done()
|
|
570
|
+
expect(map.fire).not.toHaveBeenCalled()
|
|
571
|
+
expect(draw.changeMode).not.toHaveBeenCalled()
|
|
572
|
+
})
|
|
573
|
+
})
|
|
574
|
+
|
|
575
|
+
describe('cancel', () => {
|
|
576
|
+
test('cancelling an in-progress draw clears the undo stack, trashes the sketch and disables the control', () => {
|
|
577
|
+
const { adapter, draw, undoStack } = setup()
|
|
578
|
+
draw.getMode.mockReturnValue('draw_polygon')
|
|
579
|
+
adapter.cancel()
|
|
580
|
+
expect(undoStack.clear).toHaveBeenCalled()
|
|
581
|
+
expect(draw.trash).toHaveBeenCalled()
|
|
582
|
+
expect(draw.changeMode).toHaveBeenCalledWith('disabled')
|
|
583
|
+
})
|
|
584
|
+
|
|
585
|
+
test('cancelling a draw_line session also trashes the sketch', () => {
|
|
586
|
+
const { adapter, draw } = setup()
|
|
587
|
+
draw.getMode.mockReturnValue('draw_line')
|
|
588
|
+
adapter.cancel()
|
|
589
|
+
expect(draw.trash).toHaveBeenCalled()
|
|
590
|
+
})
|
|
591
|
+
|
|
592
|
+
// Regression: events.js's handleCancel already restores the original feature
|
|
593
|
+
// via draw.add() before calling this. trash() runs mapbox-gl-draw's
|
|
594
|
+
// direct_select onTrash handler, which operates on the mode's own live
|
|
595
|
+
// state — removing the selected vertex or (if the in-progress edit left the
|
|
596
|
+
// shape invalid) deleting the whole feature — silently discarding the
|
|
597
|
+
// just-restored original. See MaplibreDrawAdapter.js's cancel() comment.
|
|
598
|
+
test('cancelling an edit session does NOT trash — the restored feature must survive', () => {
|
|
599
|
+
const { adapter, draw, undoStack } = setup()
|
|
600
|
+
draw.getMode.mockReturnValue('edit_vertex')
|
|
601
|
+
adapter.cancel()
|
|
602
|
+
expect(undoStack.clear).toHaveBeenCalled()
|
|
603
|
+
expect(draw.trash).not.toHaveBeenCalled()
|
|
604
|
+
expect(draw.changeMode).toHaveBeenCalledWith('disabled')
|
|
605
|
+
})
|
|
606
|
+
|
|
607
|
+
test('cancelling with no active session (disabled mode) does not trash', () => {
|
|
608
|
+
const { adapter, draw } = setup()
|
|
609
|
+
adapter.cancel()
|
|
610
|
+
expect(draw.trash).not.toHaveBeenCalled()
|
|
611
|
+
expect(draw.changeMode).toHaveBeenCalledWith('disabled')
|
|
612
|
+
})
|
|
613
|
+
})
|
|
614
|
+
|
|
615
|
+
describe('setSnapEnabled', () => {
|
|
616
|
+
test('enables snapping via the snap instance', () => {
|
|
617
|
+
const { adapter, mapProvider } = setup()
|
|
618
|
+
const snap = { setSnapStatus: jest.fn() }
|
|
619
|
+
getSnapInstance.mockReturnValue(snap)
|
|
620
|
+
|
|
621
|
+
adapter.setSnapEnabled(true)
|
|
622
|
+
|
|
623
|
+
expect(mapProvider.snapEnabled).toBe(true)
|
|
624
|
+
expect(snap.setSnapStatus).toHaveBeenCalledWith(true)
|
|
625
|
+
expect(clearSnapState).not.toHaveBeenCalled()
|
|
626
|
+
})
|
|
627
|
+
|
|
628
|
+
test('disabling clears snap state and hides the indicator when present', () => {
|
|
629
|
+
const { adapter, map } = setup()
|
|
630
|
+
const snap = { setSnapStatus: jest.fn() }
|
|
631
|
+
getSnapInstance.mockReturnValue(snap)
|
|
632
|
+
map.getLayer.mockReturnValue({ id: SNAP_LAYER })
|
|
633
|
+
|
|
634
|
+
adapter.setSnapEnabled(false)
|
|
635
|
+
|
|
636
|
+
expect(snap.setSnapStatus).toHaveBeenCalledWith(false)
|
|
637
|
+
expect(clearSnapState).toHaveBeenCalledWith(snap)
|
|
638
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith(SNAP_LAYER, 'visibility', 'none')
|
|
639
|
+
})
|
|
640
|
+
|
|
641
|
+
test('disabling without the indicator layer skips the layout update', () => {
|
|
642
|
+
const { adapter, map } = setup()
|
|
643
|
+
const snap = { setSnapStatus: jest.fn() }
|
|
644
|
+
getSnapInstance.mockReturnValue(snap)
|
|
645
|
+
map.getLayer.mockReturnValue(null)
|
|
646
|
+
|
|
647
|
+
adapter.setSnapEnabled(false)
|
|
648
|
+
|
|
649
|
+
expect(clearSnapState).toHaveBeenCalledWith(snap)
|
|
650
|
+
expect(map.setLayoutProperty).not.toHaveBeenCalled()
|
|
651
|
+
})
|
|
652
|
+
|
|
653
|
+
test('tolerates a missing snap instance', () => {
|
|
654
|
+
const { adapter, mapProvider } = setup()
|
|
655
|
+
getSnapInstance.mockReturnValue(null)
|
|
656
|
+
|
|
657
|
+
adapter.setSnapEnabled(false)
|
|
658
|
+
|
|
659
|
+
expect(mapProvider.snapEnabled).toBe(false)
|
|
660
|
+
expect(clearSnapState).not.toHaveBeenCalled()
|
|
661
|
+
})
|
|
662
|
+
|
|
663
|
+
test('tolerates a snap instance without setSnapStatus', () => {
|
|
664
|
+
const { adapter } = setup()
|
|
665
|
+
getSnapInstance.mockReturnValue({})
|
|
666
|
+
expect(() => adapter.setSnapEnabled(true)).not.toThrow()
|
|
667
|
+
})
|
|
668
|
+
})
|
|
669
|
+
|
|
670
|
+
describe('setSnapLayers', () => {
|
|
671
|
+
test('forwards layers to the snap instance when available', () => {
|
|
672
|
+
const { adapter } = setup()
|
|
673
|
+
const snap = { setSnapLayers: jest.fn() }
|
|
674
|
+
getSnapInstance.mockReturnValue(snap)
|
|
675
|
+
|
|
676
|
+
adapter.setSnapLayers(['a', 'b'])
|
|
677
|
+
expect(snap.setSnapLayers).toHaveBeenCalledWith(['a', 'b'])
|
|
678
|
+
})
|
|
679
|
+
|
|
680
|
+
test('stashes pending layers when the instance is not ready', () => {
|
|
681
|
+
const { adapter, map } = setup()
|
|
682
|
+
getSnapInstance.mockReturnValue(null)
|
|
683
|
+
|
|
684
|
+
adapter.setSnapLayers(['a'])
|
|
685
|
+
expect(map._pendingSnapLayers).toEqual(['a'])
|
|
686
|
+
})
|
|
687
|
+
|
|
688
|
+
test('does nothing when there is no instance and no layers', () => {
|
|
689
|
+
const { adapter, map } = setup()
|
|
690
|
+
getSnapInstance.mockReturnValue(null)
|
|
691
|
+
|
|
692
|
+
adapter.setSnapLayers(null)
|
|
693
|
+
expect(map._pendingSnapLayers).toBeUndefined()
|
|
694
|
+
})
|
|
695
|
+
})
|
|
696
|
+
|
|
697
|
+
describe('_handleModeChange', () => {
|
|
698
|
+
test('clears the snap indicator when leaving to a non-draw mode', () => {
|
|
699
|
+
const { map } = setup()
|
|
700
|
+
const snap = { id: 'snap' }
|
|
701
|
+
getSnapInstance.mockReturnValue(snap)
|
|
702
|
+
|
|
703
|
+
onHandler(map, MAPBOX_DRAW_EVENTS.MODE_CHANGE)({ mode: 'simple_select' })
|
|
704
|
+
|
|
705
|
+
expect(clearSnapIndicator).toHaveBeenCalledWith(snap, map)
|
|
706
|
+
})
|
|
707
|
+
|
|
708
|
+
test('keeps the snap indicator while in a draw mode', () => {
|
|
709
|
+
const { map } = setup()
|
|
710
|
+
onHandler(map, MAPBOX_DRAW_EVENTS.MODE_CHANGE)({ mode: 'draw_polygon' })
|
|
711
|
+
expect(clearSnapIndicator).not.toHaveBeenCalled()
|
|
712
|
+
})
|
|
713
|
+
|
|
714
|
+
test('keeps the snap indicator while in edit_vertex mode', () => {
|
|
715
|
+
const { map } = setup()
|
|
716
|
+
onHandler(map, MAPBOX_DRAW_EVENTS.MODE_CHANGE)({ mode: 'edit_vertex' })
|
|
717
|
+
expect(clearSnapIndicator).not.toHaveBeenCalled()
|
|
718
|
+
})
|
|
719
|
+
})
|
|
720
|
+
|
|
721
|
+
describe('_handleStyleData', () => {
|
|
722
|
+
test('does nothing when there are no layers', () => {
|
|
723
|
+
const { map } = setup()
|
|
724
|
+
map.getStyle.mockReturnValue({ layers: undefined })
|
|
725
|
+
onHandler(map, STYLE_DATA_EVENT)()
|
|
726
|
+
expect(map.moveLayer).not.toHaveBeenCalled()
|
|
727
|
+
})
|
|
728
|
+
|
|
729
|
+
test('does nothing when a draw layer is already on top', () => {
|
|
730
|
+
const { map } = setup()
|
|
731
|
+
map.getStyle.mockReturnValue({ layers: [{ id: 'a', source: 'bg' }, { id: 'd', source: 'mapbox-gl-draw-hot' }] })
|
|
732
|
+
onHandler(map, STYLE_DATA_EVENT)()
|
|
733
|
+
expect(map.moveLayer).not.toHaveBeenCalled()
|
|
734
|
+
})
|
|
735
|
+
|
|
736
|
+
test('moves draw layers back to the top when covered', () => {
|
|
737
|
+
const { map } = setup()
|
|
738
|
+
map.getStyle.mockReturnValue({
|
|
739
|
+
layers: [
|
|
740
|
+
{ id: 'd1', source: 'mapbox-gl-draw-hot' },
|
|
741
|
+
{ id: 'd2', source: 'mapbox-gl-draw-cold' },
|
|
742
|
+
{ id: 'top', source: 'other' }
|
|
743
|
+
]
|
|
744
|
+
})
|
|
745
|
+
|
|
746
|
+
onHandler(map, STYLE_DATA_EVENT)()
|
|
747
|
+
|
|
748
|
+
expect(map.moveLayer).toHaveBeenCalledWith('d1')
|
|
749
|
+
expect(map.moveLayer).toHaveBeenCalledWith('d2')
|
|
750
|
+
expect(map.moveLayer).not.toHaveBeenCalledWith('top')
|
|
751
|
+
})
|
|
752
|
+
|
|
753
|
+
test('tolerates layers without a source', () => {
|
|
754
|
+
const { map } = setup()
|
|
755
|
+
map.getStyle.mockReturnValue({ layers: [{ id: 'd', source: 'mapbox-gl-draw-hot' }, { id: 'nosrc' }] })
|
|
756
|
+
onHandler(map, STYLE_DATA_EVENT)()
|
|
757
|
+
expect(map.moveLayer).toHaveBeenCalledWith('d')
|
|
758
|
+
})
|
|
759
|
+
|
|
760
|
+
test('re-asserts a dashed stroke after a style reload resets layer visibility', () => {
|
|
761
|
+
const { adapter, map, draw } = setup()
|
|
762
|
+
draw.getMode.mockReturnValue('draw_polygon')
|
|
763
|
+
map.getLayer.mockReturnValue({})
|
|
764
|
+
// Live check flags a crossing → dashed.
|
|
765
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE)({ type: 'draw.geometrychange', coordinates: [[[0, 0], [10, 10], [10, 0], [0, 10]]] })
|
|
766
|
+
expect(adapter).toBeDefined()
|
|
767
|
+
// A style reload re-adds the layers with spec defaults (solid visible)…
|
|
768
|
+
map.setLayoutProperty.mockClear()
|
|
769
|
+
onHandler(map, STYLE_DATA_EVENT)()
|
|
770
|
+
// …and the handler re-applies the cached dashed state.
|
|
771
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active-invalid.hot', 'visibility', 'visible')
|
|
772
|
+
expect(map.setLayoutProperty).toHaveBeenCalledWith('stroke-active.hot', 'visibility', 'none')
|
|
773
|
+
})
|
|
774
|
+
})
|
|
775
|
+
|
|
776
|
+
describe('interface-type normalisation', () => {
|
|
777
|
+
test('draw.interfacetypechange is forwarded onto the adapter bus', () => {
|
|
778
|
+
const { map, bus } = setup()
|
|
779
|
+
onHandler(map, CUSTOM_DRAW_EVENTS.INTERFACE_TYPE_CHANGE)({ interfaceType: 'keyboard' })
|
|
780
|
+
expect(bus.emit).toHaveBeenCalledWith('interfacetypechange', { interfaceType: 'keyboard' })
|
|
781
|
+
})
|
|
782
|
+
})
|
|
783
|
+
|
|
784
|
+
describe('remove', () => {
|
|
785
|
+
test('unsubscribes from every event and cleans up the draw control', () => {
|
|
786
|
+
const { adapter, map, removeDraw } = setup()
|
|
787
|
+
|
|
788
|
+
adapter.remove()
|
|
789
|
+
|
|
790
|
+
const unsubscribed = map.off.mock.calls.map(([name]) => name)
|
|
791
|
+
expect(unsubscribed).toEqual(expect.arrayContaining([
|
|
792
|
+
MAPBOX_DRAW_EVENTS.CREATE, MAPBOX_DRAW_EVENTS.UPDATE, MAPBOX_DRAW_EVENTS.MODE_CHANGE,
|
|
793
|
+
CUSTOM_DRAW_EVENTS.EDIT_FINISH, CUSTOM_DRAW_EVENTS.CANCEL, CUSTOM_DRAW_EVENTS.VERTEX_SELECTION,
|
|
794
|
+
CUSTOM_DRAW_EVENTS.VERTEX_CHANGE, CUSTOM_DRAW_EVENTS.UNDO_CHANGE, CUSTOM_DRAW_EVENTS.GEOMETRY_CHANGE,
|
|
795
|
+
STYLE_DATA_EVENT
|
|
796
|
+
]))
|
|
797
|
+
expect(removeDraw).toHaveBeenCalled()
|
|
798
|
+
})
|
|
799
|
+
})
|