@defra/interactive-map 0.0.3-alpha → 0.0.5-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/README.md +16 -57
- package/dist/css/index.css +1 -1
- package/dist/esm/im-core.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/umd/im-core.js +1 -1
- package/dist/umd/index.js +1 -1
- package/docs/api/button-definition.md +176 -0
- package/docs/api/context.md +124 -0
- package/docs/api/control-definition.md +72 -0
- package/docs/api/icon-definition.md +28 -0
- package/docs/api/map-style-config.md +76 -0
- package/docs/api/marker-config.md +51 -0
- package/docs/api/panel-definition.md +117 -0
- package/docs/api/slots.md +25 -0
- package/docs/api.md +721 -0
- package/docs/architecture.md +139 -0
- package/docs/building-a-plugin.md +149 -0
- package/docs/getting-started.md +46 -0
- package/docs/govuk-prototype.md +0 -0
- package/docs/plugins/interact.md +205 -0
- package/docs/plugins/map-styles.md +84 -0
- package/docs/plugins/plugin-context.md +67 -0
- package/docs/plugins/plugin-descriptor.md +71 -0
- package/docs/plugins/plugin-manifest.md +118 -0
- package/docs/plugins/scale-bar.md +62 -0
- package/docs/plugins/search.md +162 -0
- package/docs/plugins.md +116 -0
- package/govuk-prototype-kit.config.json +7 -7
- package/package.json +16 -2
- package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +2 -0
- package/plugins/beta/datasets/dist/esm/index.js +2 -0
- package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +2 -0
- package/plugins/beta/datasets/dist/umd/index.js +2 -0
- package/plugins/beta/datasets/src/datasets.js +113 -0
- package/plugins/beta/datasets/src/fetch/createDynamicSource.js +206 -0
- package/plugins/beta/datasets/src/fetch/fetchGeoJSON.js +38 -0
- package/plugins/{datasets → beta/datasets}/src/handleSetMapStyle.js +8 -1
- package/plugins/{datasets → beta/datasets}/src/manifest.js +1 -1
- package/plugins/{datasets → beta/datasets}/src/mapLayers.js +42 -4
- package/plugins/{datasets → beta/datasets}/src/panels/Key.jsx +1 -1
- package/plugins/beta/datasets/src/utils/bbox.js +115 -0
- package/plugins/beta/draw-ml/dist/css/index.css +1 -0
- package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -0
- package/plugins/beta/draw-ml/dist/esm/index.js +2 -0
- package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -0
- package/plugins/beta/draw-ml/dist/umd/index.js +2 -0
- package/plugins/beta/draw-ml/src/api/addFeature.js +27 -0
- package/plugins/{draw-ml → beta/draw-ml}/src/api/editFeature.js +17 -6
- package/plugins/beta/draw-ml/src/api/merge.js +9 -0
- package/plugins/beta/draw-ml/src/api/newLine.js +68 -0
- package/plugins/beta/draw-ml/src/api/newPolygon.js +68 -0
- package/plugins/beta/draw-ml/src/api/split.js +81 -0
- package/plugins/{draw-ml → beta/draw-ml}/src/defaults.js +3 -0
- package/plugins/beta/draw-ml/src/draw.scss +32 -0
- package/plugins/beta/draw-ml/src/events.js +171 -0
- package/plugins/beta/draw-ml/src/manifest.js +132 -0
- package/plugins/{draw-ml → beta/draw-ml}/src/mapboxDraw.js +51 -2
- package/plugins/{draw-ml → beta/draw-ml}/src/mapboxSnap.js +18 -12
- package/plugins/beta/draw-ml/src/modes/createDrawMode.js +497 -0
- package/plugins/beta/draw-ml/src/modes/drawLineMode.js +18 -0
- package/plugins/beta/draw-ml/src/modes/drawPolygonMode.js +16 -0
- package/plugins/beta/draw-ml/src/modes/editVertex/geometryHelpers.js +135 -0
- package/plugins/beta/draw-ml/src/modes/editVertex/helpers.js +2 -0
- package/plugins/beta/draw-ml/src/modes/editVertex/touchHandlers.js +134 -0
- package/plugins/beta/draw-ml/src/modes/editVertex/undoHandlers.js +133 -0
- package/plugins/beta/draw-ml/src/modes/editVertex/vertexOperations.js +141 -0
- package/plugins/beta/draw-ml/src/modes/editVertex/vertexQueries.js +121 -0
- package/plugins/beta/draw-ml/src/modes/editVertexMode.js +437 -0
- package/plugins/{draw-ml → beta/draw-ml}/src/reducer.js +30 -2
- package/plugins/{draw-ml → beta/draw-ml}/src/styles.js +66 -36
- package/plugins/beta/draw-ml/src/undoStack.js +50 -0
- package/plugins/beta/draw-ml/src/utils/debounce.js +16 -0
- package/plugins/beta/draw-ml/src/utils/flattenStyleProperties.js +49 -0
- package/plugins/beta/draw-ml/src/utils/spatial.js +258 -0
- package/plugins/beta/frame/dist/esm/im-frame-plugin.js +1 -0
- package/plugins/beta/frame/dist/esm/index.js +2 -0
- package/plugins/beta/frame/dist/umd/im-frame-plugin.js +1 -0
- package/plugins/beta/frame/dist/umd/index.js +2 -0
- package/plugins/{frame → beta/frame}/src/Frame.jsx +1 -1
- package/plugins/{map-styles → beta/map-styles}/dist/css/index.css +1 -1
- package/plugins/beta/map-styles/dist/esm/im-map-styles-plugin.js +1 -0
- package/plugins/beta/map-styles/dist/esm/index.js +2 -0
- package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -0
- package/plugins/beta/map-styles/dist/umd/index.js +2 -0
- package/plugins/{map-styles → beta/map-styles}/src/MapStyles.jsx +1 -1
- package/plugins/{map-styles → beta/map-styles}/src/manifest.js +8 -10
- package/plugins/{map-styles → beta/map-styles}/src/mapStyles.scss +4 -1
- package/plugins/beta/scale-bar/dist/esm/im-scale-bar-plugin.js +1 -0
- package/plugins/beta/scale-bar/dist/esm/index.js +2 -0
- package/plugins/beta/scale-bar/dist/umd/im-scale-bar-plugin.js +1 -0
- package/plugins/beta/scale-bar/dist/umd/index.js +2 -0
- package/plugins/beta/use-location/dist/esm/im-use-location-plugin.js +1 -0
- package/plugins/beta/use-location/dist/esm/index.js +2 -0
- package/plugins/beta/use-location/dist/umd/im-use-location-plugin.js +1 -0
- package/plugins/beta/use-location/dist/umd/index.js +2 -0
- package/plugins/interact/dist/css/index.css +1 -1
- package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
- package/plugins/interact/dist/esm/index.js +1 -1
- package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
- package/plugins/interact/dist/umd/index.js +1 -1
- package/plugins/interact/src/InteractInit.jsx +1 -1
- package/plugins/interact/src/InteractInit.test.js +97 -0
- package/plugins/interact/src/api/clear.test.js +18 -0
- package/plugins/interact/src/api/disable.test.js +12 -0
- package/plugins/interact/src/api/enable.test.js +48 -0
- package/plugins/interact/src/api/selectFeature.test.js +33 -0
- package/plugins/interact/src/api/unselectFeature.test.js +33 -0
- package/plugins/interact/src/defaults.js +2 -0
- package/plugins/interact/src/events.js +37 -52
- package/plugins/interact/src/events.test.js +186 -0
- package/plugins/interact/src/hooks/useHighlightSync.js +1 -1
- package/plugins/interact/src/hooks/useHighlightSync.test.js +212 -0
- package/plugins/interact/src/hooks/useInteractionHandlers.js +80 -41
- package/plugins/interact/src/hooks/useInteractionHandlers.test.js +316 -0
- package/plugins/interact/src/index.test.js +22 -0
- package/plugins/interact/src/interact.scss +6 -0
- package/plugins/interact/src/manifest.js +1 -1
- package/plugins/interact/src/manifest.test.js +94 -0
- package/plugins/interact/src/reducer.js +28 -21
- package/plugins/interact/src/reducer.test.js +155 -0
- package/plugins/interact/src/utils/buildStylesMap.test.js +57 -0
- package/plugins/interact/src/utils/featureQueries.js +2 -2
- package/plugins/interact/src/utils/featureQueries.test.js +56 -0
- package/plugins/interact/src/utils/spatial.js +95 -0
- package/plugins/interact/src/utils/spatial.test.js +93 -0
- 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 +2 -2
- package/plugins/search/src/components/Form/Form.jsx +1 -1
- package/plugins/search/src/components/Suggestions/Suggestions.jsx +5 -5
- package/plugins/search/src/datasets.js +1 -1
- package/plugins/search/src/defaults.js +3 -0
- package/plugins/search/src/events/fetchSuggestions.js +48 -53
- package/plugins/search/src/events/formHandlers.js +3 -2
- package/plugins/search/src/events/index.js +1 -1
- package/plugins/search/src/events/inputHandlers.js +3 -1
- package/plugins/search/src/events/suggestionHandlers.js +12 -3
- package/plugins/search/src/search.scss +4 -1
- package/plugins/search/src/utils/parseOsNamesResults.js +15 -19
- package/providers/{esri → beta/esri}/src/esriProvider.js +1 -1
- package/providers/{esri → beta/esri}/src/index.js +1 -1
- package/providers/{esri → beta/esri}/src/mapEvents.js +2 -2
- package/providers/beta/open-names/dist/esm/im-reverse-geocode.js +2 -0
- package/providers/beta/open-names/dist/esm/index.js +2 -0
- package/providers/beta/open-names/dist/umd/im-reverse-geocode.js +2 -0
- package/providers/beta/open-names/dist/umd/im-reverse-geocode.js.LICENSE.txt +1 -0
- package/providers/beta/open-names/dist/umd/index.js +2 -0
- package/providers/beta/open-names/dist/umd/index.js.LICENSE.txt +1 -0
- package/providers/maplibre/dist/esm/im-maplibre-framework.js +1 -1
- package/providers/maplibre/dist/esm/im-maplibre-framework.js.LICENSE.txt +1 -1
- package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
- package/providers/maplibre/dist/esm/index.js +1 -1
- package/providers/maplibre/dist/umd/im-maplibre-framework.js +1 -1
- package/providers/maplibre/dist/umd/im-maplibre-framework.js.LICENSE.txt +1 -1
- package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
- package/providers/maplibre/dist/umd/index.js +1 -1
- package/providers/maplibre/src/defaults.js +3 -2
- package/providers/maplibre/src/index.js +36 -20
- package/providers/maplibre/src/maplibreProvider.js +140 -11
- package/providers/maplibre/src/utils/detectWebgl.js +1 -2
- package/providers/maplibre/src/utils/highlightFeatures.js +78 -67
- package/providers/maplibre/src/utils/labels.js +174 -120
- package/providers/maplibre/src/utils/maplibreFixes.js +2 -2
- package/providers/maplibre/src/utils/queryFeatures.js +146 -0
- package/providers/maplibre/src/utils/spatial.js +14 -17
- package/sonar-project.properties +40 -3
- package/src/App/components/Actions/Actions.jsx +2 -2
- package/src/App/components/Actions/Actions.module.scss +2 -2
- package/src/App/components/KeyboardHelp/KeyboardHelp.jsx +3 -1
- package/src/App/components/KeyboardHelp/KeyboardHelp.test.jsx +9 -0
- package/src/App/components/Logo/Logo.jsx +1 -1
- package/src/App/components/MapButton/MapButton.jsx +217 -41
- package/src/App/components/MapButton/MapButton.module.scss +32 -21
- package/src/App/components/MapButton/MapButton.test.jsx +128 -84
- package/src/App/components/Markers/Markers.jsx +1 -1
- package/src/App/components/Markers/Markers.module.scss +0 -5
- package/src/App/components/Panel/Panel.jsx +75 -45
- package/src/App/components/Panel/Panel.module.scss +18 -24
- package/src/App/components/Panel/Panel.test.jsx +18 -0
- package/src/App/components/PopupMenu/PopupMenu.jsx +246 -0
- package/src/App/components/PopupMenu/PopupMenu.module.scss +70 -0
- package/src/App/components/PopupMenu/PopupMenu.test.jsx +304 -0
- package/src/App/components/Tooltip/Tooltip.jsx +4 -2
- package/src/App/components/Tooltip/getTooltipPosition.js +1 -1
- package/src/App/components/Viewport/MapController.jsx +1 -1
- package/src/App/components/Viewport/MapStatus.jsx +1 -1
- package/src/App/components/Viewport/Viewport.jsx +2 -2
- package/src/App/components/Viewport/Viewport.module.scss +2 -2
- package/src/App/controls/keyboardActions.js +3 -2
- package/src/App/controls/keyboardShortcuts.js +4 -2
- package/src/App/hooks/useButtonStateEvaluator.js +58 -45
- package/src/App/hooks/useButtonStateEvaluator.test.js +36 -3
- package/src/App/hooks/useCrossHairAPI.js +49 -47
- package/src/App/hooks/useFocusVisible.js +2 -2
- package/src/App/hooks/useInterfaceAPI.js +36 -1
- package/src/App/hooks/useKeyboardHint.js +1 -1
- package/src/App/hooks/useKeyboardShortcuts.js +4 -2
- package/src/App/hooks/useMapAnnouncements.js +34 -32
- package/src/App/hooks/useMapEvents.js +12 -1
- package/src/App/hooks/useMapProviderOverrides.js +3 -3
- package/src/App/hooks/useMapStateSync.js +7 -1
- package/src/App/hooks/useMapURLSync.js +6 -1
- package/src/App/hooks/useMarkersAPI.js +88 -50
- package/src/App/hooks/useMediaQueryDispatch.test.js +48 -0
- package/src/App/hooks/useModalPanelBehaviour.js +46 -40
- package/src/App/hooks/useResizeObserver.js +2 -2
- package/src/App/initialiseApp.js +45 -38
- package/src/App/layout/Layout.jsx +6 -4
- package/src/App/layout/layout.module.scss +13 -17
- package/src/App/registry/keyboardShortcutRegistry.js +12 -2
- package/src/App/registry/keyboardShortcutRegistry.test.js +28 -0
- package/src/App/registry/mergeManifests.js +1 -1
- package/src/App/registry/panelRegistry.js +1 -1
- package/src/App/registry/panelRegistry.test.js +30 -1
- package/src/App/registry/pluginRegistry.js +14 -51
- package/src/App/registry/pluginRegistry.test.js +54 -6
- package/src/App/renderer/HtmlElementHost.jsx +186 -0
- package/src/App/renderer/HtmlElementHost.test.jsx +231 -0
- package/src/App/renderer/mapButtons.js +12 -9
- package/src/App/renderer/mapButtons.test.js +6 -4
- package/src/App/renderer/mapControls.js +6 -0
- package/src/App/renderer/mapControls.test.js +10 -2
- package/src/App/renderer/mapPanels.js +39 -26
- package/src/App/renderer/mapPanels.test.js +29 -0
- package/src/App/renderer/pluginWrapper.test.js +28 -0
- package/src/App/renderer/slotHelpers.js +60 -0
- package/src/App/renderer/slotHelpers.test.js +82 -0
- package/src/App/store/AppProvider.jsx +3 -0
- package/src/App/store/AppProvider.test.jsx +40 -0
- package/src/App/store/PluginProvider.jsx +7 -5
- package/src/App/store/appActionsMap.js +46 -1
- package/src/App/store/appActionsMap.test.js +21 -0
- package/src/App/store/appReducer.js +1 -0
- package/src/App/store/mapActionsMap.js +12 -24
- package/src/App/store/mapReducer.js +1 -1
- package/src/InteractiveMap/InteractiveMap.js +194 -13
- package/src/InteractiveMap/InteractiveMap.test.js +164 -2
- package/src/InteractiveMap/behaviourController.js +12 -2
- package/src/InteractiveMap/behaviourController.test.js +82 -1
- package/src/InteractiveMap/deviceChecker.js +1 -1
- package/src/InteractiveMap/deviceChecker.test.js +2 -2
- package/src/InteractiveMap/historyManager.js +41 -5
- package/src/InteractiveMap/historyManager.test.js +37 -6
- package/src/InteractiveMap/polyfills.js +39 -0
- package/src/InteractiveMap/polyfills.test.js +127 -0
- package/src/config/appConfig.js +5 -5
- package/src/config/appConfig.test.js +107 -42
- package/src/config/defaults.js +30 -20
- package/src/config/events.js +110 -4
- package/src/index.js +5 -2
- package/src/index.umd.js +1 -1
- package/src/scss/main.scss +1 -0
- package/src/scss/settings/_dimensions.scss +6 -2
- package/src/scss/tools/_border-focus.scss +20 -4
- package/src/services/eventBus.test.js +24 -1
- package/src/test-utils.js +1 -0
- package/src/types.js +590 -0
- package/src/utils/detectBreakpoint.js +78 -77
- package/src/utils/detectBreakpoint.test.js +50 -4
- package/src/utils/detectInterfaceType.js +4 -4
- package/src/utils/getIsFullscreen.js +3 -1
- package/src/utils/getSafeZoneInset.js +23 -7
- package/src/utils/getSafeZoneInset.test.js +18 -0
- package/src/utils/mapStateSync.js +3 -3
- package/src/utils/queryString.js +1 -1
- package/src/utils/stringToKebab.js +1 -1
- package/src/utils/toggleInertElements.js +37 -12
- package/webpack.dev.mjs +3 -4
- package/webpack.esm.mjs +8 -8
- package/webpack.umd.mjs +8 -8
- package/plugins/datasets/dist/esm/im-datasets-plugin.js +0 -1
- package/plugins/datasets/dist/esm/index.js +0 -2
- package/plugins/datasets/dist/umd/im-datasets-plugin.js +0 -1
- package/plugins/datasets/dist/umd/index.js +0 -2
- package/plugins/datasets/src/datasets.js +0 -60
- package/plugins/datasets/src/utils/bbox.js +0 -4
- package/plugins/draw-ml/dist/css/index.css +0 -1
- package/plugins/draw-ml/dist/esm/im-draw-ml-plugin.js +0 -1
- package/plugins/draw-ml/dist/esm/index.js +0 -2
- package/plugins/draw-ml/dist/umd/im-draw-ml-plugin.js +0 -1
- package/plugins/draw-ml/dist/umd/index.js +0 -2
- package/plugins/draw-ml/src/api/addFeature.js +0 -15
- package/plugins/draw-ml/src/api/newPolygon.js +0 -43
- package/plugins/draw-ml/src/draw.scss +0 -9
- package/plugins/draw-ml/src/events.js +0 -127
- package/plugins/draw-ml/src/manifest.js +0 -100
- package/plugins/draw-ml/src/modes/drawVertexMode.js +0 -275
- package/plugins/draw-ml/src/modes/editVertexMode.js +0 -426
- package/plugins/draw-ml/src/utils.js +0 -102
- package/plugins/frame/dist/esm/im-frame-plugin.js +0 -1
- package/plugins/frame/dist/esm/index.js +0 -2
- package/plugins/frame/dist/umd/im-frame-plugin.js +0 -1
- package/plugins/frame/dist/umd/index.js +0 -2
- package/plugins/map-styles/dist/esm/im-map-styles-plugin.js +0 -1
- package/plugins/map-styles/dist/esm/index.js +0 -2
- package/plugins/map-styles/dist/umd/im-map-styles-plugin.js +0 -1
- package/plugins/map-styles/dist/umd/index.js +0 -2
- package/plugins/scale-bar/dist/esm/im-scale-bar-plugin.js +0 -1
- package/plugins/scale-bar/dist/esm/index.js +0 -2
- package/plugins/scale-bar/dist/umd/im-scale-bar-plugin.js +0 -1
- package/plugins/scale-bar/dist/umd/index.js +0 -2
- package/plugins/search/src/utils/fetchDataset.js +0 -23
- package/plugins/use-location/dist/esm/im-use-location-plugin.js +0 -1
- package/plugins/use-location/dist/esm/index.js +0 -2
- package/plugins/use-location/dist/umd/im-use-location-plugin.js +0 -1
- package/plugins/use-location/dist/umd/index.js +0 -2
- package/providers/maplibre/dist/esm/im-maplibre-legacy-framework.js +0 -1
- package/providers/maplibre/dist/umd/im-maplibre-legacy-framework.js +0 -1
- package/providers/open-names/dist/esm/im-reverse-geocode.js +0 -2
- package/providers/open-names/dist/esm/index.js +0 -2
- package/providers/open-names/dist/umd/im-reverse-geocode.js +0 -2
- package/providers/open-names/dist/umd/index.js +0 -2
- /package/docs/architecture/{ARCHITECTURE_DIAGRAMS.md → architecture-diagrams.md} +0 -0
- /package/plugins/{datasets → beta/datasets}/dist/css/index.css +0 -0
- /package/plugins/{datasets/dist/esm/index.js.LICENSE.txt → beta/datasets/dist/esm/im-datasets-plugin.js.LICENSE.txt} +0 -0
- /package/plugins/{datasets/dist/umd → beta/datasets/dist/esm}/index.js.LICENSE.txt +0 -0
- /package/plugins/{draw-ml/dist/esm/index.js.LICENSE.txt → beta/datasets/dist/umd/im-datasets-plugin.js.LICENSE.txt} +0 -0
- /package/plugins/{draw-ml → beta/datasets}/dist/umd/index.js.LICENSE.txt +0 -0
- /package/plugins/{datasets → beta/datasets}/src/DatasetsInit.jsx +0 -0
- /package/plugins/{datasets → beta/datasets}/src/api/addDataset.js +0 -0
- /package/plugins/{datasets → beta/datasets}/src/api/hideDataset.js +0 -0
- /package/plugins/{datasets → beta/datasets}/src/api/hideFeatures.js +0 -0
- /package/plugins/{datasets → beta/datasets}/src/api/removeDataset.js +0 -0
- /package/plugins/{datasets → beta/datasets}/src/api/showDataset.js +0 -0
- /package/plugins/{datasets → beta/datasets}/src/api/showFeatures.js +0 -0
- /package/plugins/{datasets → beta/datasets}/src/datasets.scss +0 -0
- /package/plugins/{datasets → beta/datasets}/src/defaults.js +0 -0
- /package/plugins/{datasets → beta/datasets}/src/index.js +0 -0
- /package/plugins/{datasets → beta/datasets}/src/panels/Key.module.scss +0 -0
- /package/plugins/{datasets → beta/datasets}/src/panels/Layers.jsx +0 -0
- /package/plugins/{datasets → beta/datasets}/src/panels/Layers.module.scss +0 -0
- /package/plugins/{datasets → beta/datasets}/src/reducer.js +0 -0
- /package/plugins/{datasets → beta/datasets}/src/utils/debounce.js +0 -0
- /package/plugins/{datasets → beta/datasets}/src/utils/filters.js +0 -0
- /package/plugins/{draw-es → beta/draw-es}/src/DrawInit.jsx +0 -0
- /package/plugins/{draw-es → beta/draw-es}/src/api/addFeature.js +0 -0
- /package/plugins/{draw-es → beta/draw-es}/src/api/deleteFeature.js +0 -0
- /package/plugins/{draw-es → beta/draw-es}/src/api/editFeature.js +0 -0
- /package/plugins/{draw-es → beta/draw-es}/src/api/newPolygon.js +0 -0
- /package/plugins/{draw-es → beta/draw-es}/src/events.js +0 -0
- /package/plugins/{draw-es → beta/draw-es}/src/graphic.js +0 -0
- /package/plugins/{draw-es → beta/draw-es}/src/index.js +0 -0
- /package/plugins/{draw-es → beta/draw-es}/src/manifest.js +0 -0
- /package/plugins/{draw-es → beta/draw-es}/src/reducer.js +0 -0
- /package/plugins/{draw-es → beta/draw-es}/src/sketchViewModel.js +0 -0
- /package/plugins/{frame → beta/draw-ml}/dist/esm/index.js.LICENSE.txt +0 -0
- /package/plugins/{frame → beta/draw-ml}/dist/umd/index.js.LICENSE.txt +0 -0
- /package/plugins/{draw-ml → beta/draw-ml}/src/DrawInit.jsx +0 -0
- /package/plugins/{draw-ml → beta/draw-ml}/src/api/deleteFeature.js +0 -0
- /package/plugins/{draw-ml → beta/draw-ml}/src/index.js +0 -0
- /package/plugins/{draw-ml → beta/draw-ml}/src/modes/disabledMode.js +0 -0
- /package/plugins/{draw-ml/src → beta/draw-ml/src/utils}/snapHelpers.js +0 -0
- /package/plugins/{frame → beta/frame}/dist/css/index.css +0 -0
- /package/plugins/{map-styles → beta/frame}/dist/esm/index.js.LICENSE.txt +0 -0
- /package/plugins/{map-styles → beta/frame}/dist/umd/index.js.LICENSE.txt +0 -0
- /package/plugins/{frame → beta/frame}/package.json +0 -0
- /package/plugins/{frame → beta/frame}/src/FrameInit.jsx +0 -0
- /package/plugins/{frame → beta/frame}/src/api/addFrame.js +0 -0
- /package/plugins/{frame → beta/frame}/src/api/editFeature.js +0 -0
- /package/plugins/{frame → beta/frame}/src/config.js +0 -0
- /package/plugins/{frame → beta/frame}/src/frame.scss +0 -0
- /package/plugins/{frame → beta/frame}/src/index.js +0 -0
- /package/plugins/{frame → beta/frame}/src/manifest.js +0 -0
- /package/plugins/{frame → beta/frame}/src/reducer.js +0 -0
- /package/plugins/{frame → beta/frame}/src/utils.js +0 -0
- /package/plugins/{scale-bar → beta/map-styles}/dist/esm/index.js.LICENSE.txt +0 -0
- /package/plugins/{scale-bar → beta/map-styles}/dist/umd/index.js.LICENSE.txt +0 -0
- /package/plugins/{map-styles → beta/map-styles}/src/MapStylesInit.jsx +0 -0
- /package/plugins/{map-styles → beta/map-styles}/src/config.js +0 -0
- /package/plugins/{map-styles → beta/map-styles}/src/index.js +0 -0
- /package/plugins/{scale-bar → beta/scale-bar}/dist/css/index.css +0 -0
- /package/plugins/{use-location → beta/scale-bar}/dist/esm/index.js.LICENSE.txt +0 -0
- /package/plugins/{use-location → beta/scale-bar}/dist/umd/index.js.LICENSE.txt +0 -0
- /package/plugins/{scale-bar → beta/scale-bar}/package.json +0 -0
- /package/plugins/{scale-bar → beta/scale-bar}/src/ScaleBar.jsx +0 -0
- /package/plugins/{scale-bar → beta/scale-bar}/src/ScaleBar.test.jsx +0 -0
- /package/plugins/{scale-bar → beta/scale-bar}/src/index.js +0 -0
- /package/plugins/{scale-bar → beta/scale-bar}/src/index.test.js +0 -0
- /package/plugins/{scale-bar → beta/scale-bar}/src/manifest.js +0 -0
- /package/plugins/{scale-bar → beta/scale-bar}/src/scaleBar.scss +0 -0
- /package/plugins/{scale-bar → beta/scale-bar}/src/utils.js +0 -0
- /package/plugins/{scale-bar → beta/scale-bar}/src/utils.test.js +0 -0
- /package/{providers/open-names → plugins/beta/use-location}/dist/esm/index.js.LICENSE.txt +0 -0
- /package/{providers/open-names → plugins/beta/use-location}/dist/umd/index.js.LICENSE.txt +0 -0
- /package/plugins/{use-location → beta/use-location}/src/UseLocation.jsx +0 -0
- /package/plugins/{use-location → beta/use-location}/src/UseLocationInit.jsx +0 -0
- /package/plugins/{use-location → beta/use-location}/src/defaults.js +0 -0
- /package/plugins/{use-location → beta/use-location}/src/events.js +0 -0
- /package/plugins/{use-location → beta/use-location}/src/index.js +0 -0
- /package/plugins/{use-location → beta/use-location}/src/manifest.js +0 -0
- /package/plugins/{use-location → beta/use-location}/src/reducer.js +0 -0
- /package/providers/{esri → beta/esri}/src/appEvents.js +0 -0
- /package/providers/{esri → beta/esri}/src/defaults.js +0 -0
- /package/providers/{esri → beta/esri}/src/esriProvider.scss +0 -0
- /package/providers/{esri → beta/esri}/src/utils/coords.js +0 -0
- /package/providers/{esri → beta/esri}/src/utils/detectWebGL.js +0 -0
- /package/providers/{esri → beta/esri}/src/utils/esriFixes.js +0 -0
- /package/providers/{esri → beta/esri}/src/utils/query.js +0 -0
- /package/providers/{esri → beta/esri}/src/utils/spatial.js +0 -0
- /package/providers/{open-names → beta/open-names}/dist/esm/im-reverse-geocode.js.LICENSE.txt +0 -0
- /package/providers/{open-names/dist/umd/im-reverse-geocode.js.LICENSE.txt → beta/open-names/dist/esm/index.js.LICENSE.txt} +0 -0
- /package/providers/{open-names → beta/open-names}/src/index.js +0 -0
- /package/providers/{open-names → beta/open-names}/src/reverseGeocode.js +0 -0
- /package/providers/{open-names → beta/open-names}/src/utils/mapToLocationModel.js +0 -0
|
@@ -35,11 +35,12 @@ export const createKeyboardActions = (mapProvider, announce, {
|
|
|
35
35
|
|
|
36
36
|
zoomOut: (e) => mapProvider.zoomOut(getZoom(e.shiftKey)),
|
|
37
37
|
|
|
38
|
-
getInfo: async (
|
|
38
|
+
getInfo: async (_e) => {
|
|
39
39
|
const coord = mapProvider.getCenter()
|
|
40
40
|
const place = await reverseGeocode(mapProvider.getZoom(), coord)
|
|
41
41
|
const area = mapProvider.getAreaDimensions?.()
|
|
42
|
-
|
|
42
|
+
const message = area ? `${place}. Covering ${area}.` : `${place}.`
|
|
43
|
+
announce(message, 'core')
|
|
43
44
|
},
|
|
44
45
|
|
|
45
46
|
highlightNextLabel: (e) => {
|
|
@@ -48,13 +48,15 @@ export const coreShortcuts = [
|
|
|
48
48
|
group: 'Labels',
|
|
49
49
|
title: 'Highlight label at centre',
|
|
50
50
|
command: '<kbd>Alt</kbd> + <kbd>Enter</kbd>',
|
|
51
|
-
enabled: false
|
|
51
|
+
enabled: false,
|
|
52
|
+
requiredConfig: ['readMapText']
|
|
52
53
|
},
|
|
53
54
|
{
|
|
54
55
|
id: 'highlightNextLabel',
|
|
55
56
|
group: 'Labels',
|
|
56
57
|
title: 'Highlight nearby label',
|
|
57
58
|
command: '<kbd>Alt</kbd> + <kbd>→</kbd>, <kbd>←</kbd>, <kbd>↑</kbd> or <kbd>↓</kbd>',
|
|
58
|
-
enabled: false
|
|
59
|
+
enabled: false,
|
|
60
|
+
requiredConfig: ['readMapText']
|
|
59
61
|
}
|
|
60
62
|
]
|
|
@@ -4,6 +4,52 @@ import { useApp } from '../store/appContext.js'
|
|
|
4
4
|
import { useConfig } from '../store/configContext.js'
|
|
5
5
|
import { PluginContext } from '../store/PluginProvider.jsx'
|
|
6
6
|
|
|
7
|
+
function evaluateButtonState ({ btn, pluginId, appState, dispatch, evaluateProp }) {
|
|
8
|
+
const checks = [{
|
|
9
|
+
prop: 'enableWhen',
|
|
10
|
+
state: appState.disabledButtons,
|
|
11
|
+
action: 'TOGGLE_BUTTON_DISABLED',
|
|
12
|
+
invert: true,
|
|
13
|
+
key: 'isDisabled'
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
prop: 'hiddenWhen',
|
|
17
|
+
state: appState.hiddenButtons,
|
|
18
|
+
action: 'TOGGLE_BUTTON_HIDDEN',
|
|
19
|
+
key: 'isHidden'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
prop: 'pressedWhen',
|
|
23
|
+
state: appState.pressedButtons,
|
|
24
|
+
action: 'TOGGLE_BUTTON_PRESSED',
|
|
25
|
+
key: 'isPressed'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
prop: 'expandedWhen',
|
|
29
|
+
state: appState.expandedButtons,
|
|
30
|
+
action: 'TOGGLE_BUTTON_EXPANDED',
|
|
31
|
+
key: 'isExpanded'
|
|
32
|
+
}]
|
|
33
|
+
|
|
34
|
+
checks.forEach(({ prop, state, action, key, invert }) => {
|
|
35
|
+
if (typeof btn[prop] !== 'function') {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const result = evaluateProp(btn[prop], pluginId)
|
|
41
|
+
const next = invert ? !result : result
|
|
42
|
+
const current = state.has(btn.id)
|
|
43
|
+
|
|
44
|
+
if (current !== next) {
|
|
45
|
+
dispatch({ type: action, payload: { id: btn.id, [key]: next } })
|
|
46
|
+
}
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.warn(`${prop} error for button ${btn.id}:`, err)
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
7
53
|
export function useButtonStateEvaluator (evaluateProp) {
|
|
8
54
|
const appState = useApp()
|
|
9
55
|
const { pluginRegistry } = useConfig()
|
|
@@ -13,54 +59,21 @@ export function useButtonStateEvaluator (evaluateProp) {
|
|
|
13
59
|
if (!appState?.dispatch || !pluginContext) {
|
|
14
60
|
return
|
|
15
61
|
}
|
|
16
|
-
const { dispatch } = appState
|
|
17
62
|
|
|
18
|
-
|
|
19
|
-
const buttons = plugin?.manifest?.buttons || []
|
|
20
|
-
|
|
21
|
-
buttons.forEach((btn) => {
|
|
22
|
-
const pluginId = plugin.id
|
|
23
|
-
|
|
24
|
-
// EnableWhen
|
|
25
|
-
if (typeof btn.enableWhen === 'function') {
|
|
26
|
-
try {
|
|
27
|
-
const shouldBeEnabled = evaluateProp(btn.enableWhen, pluginId)
|
|
28
|
-
const currentlyDisabled = appState.disabledButtons.has(btn.id)
|
|
29
|
-
const isDisabled = !shouldBeEnabled
|
|
30
|
-
if (currentlyDisabled !== isDisabled) {
|
|
31
|
-
dispatch({ type: 'TOGGLE_BUTTON_DISABLED', payload: { id: btn.id, isDisabled } })
|
|
32
|
-
}
|
|
33
|
-
} catch (err) {
|
|
34
|
-
console.warn(`enableWhen error for button ${btn.id}:`, err)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
63
|
+
const { dispatch } = appState
|
|
37
64
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const shouldBeHidden = evaluateProp(btn.hiddenWhen, pluginId)
|
|
42
|
-
const currentlyHidden = appState.hiddenButtons.has(btn.id)
|
|
43
|
-
if (currentlyHidden !== shouldBeHidden) {
|
|
44
|
-
dispatch({ type: 'TOGGLE_BUTTON_HIDDEN', payload: { id: btn.id, isHidden: shouldBeHidden } })
|
|
45
|
-
}
|
|
46
|
-
} catch (err) {
|
|
47
|
-
console.warn(`hiddenWhen error for button ${btn.id}:`, err)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
65
|
+
pluginRegistry.registeredPlugins.forEach(plugin => {
|
|
66
|
+
const buttons = (plugin?.manifest?.buttons ?? []).flatMap(b => [b, ...(b.menuItems ?? [])])
|
|
50
67
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
console.warn(`pressedWhen error for button ${btn.id}:`, err)
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
})
|
|
68
|
+
buttons.forEach(btn =>
|
|
69
|
+
evaluateButtonState({
|
|
70
|
+
btn,
|
|
71
|
+
pluginId: plugin.id,
|
|
72
|
+
appState,
|
|
73
|
+
dispatch,
|
|
74
|
+
evaluateProp
|
|
75
|
+
})
|
|
76
|
+
)
|
|
64
77
|
})
|
|
65
78
|
}, [appState, pluginContext, evaluateProp])
|
|
66
79
|
}
|
|
@@ -21,6 +21,7 @@ describe('useButtonStateEvaluator', () => {
|
|
|
21
21
|
disabledButtons: new Set(),
|
|
22
22
|
hiddenButtons: new Set(),
|
|
23
23
|
pressedButtons: new Set(),
|
|
24
|
+
expandedButtons: new Set(),
|
|
24
25
|
dispatch: mockDispatch
|
|
25
26
|
}
|
|
26
27
|
useApp.mockReturnValue(mockAppState)
|
|
@@ -89,15 +90,30 @@ describe('useButtonStateEvaluator', () => {
|
|
|
89
90
|
})
|
|
90
91
|
})
|
|
91
92
|
|
|
93
|
+
it('toggles button expanded state based on expandedWhen', () => {
|
|
94
|
+
mockPluginRegistry.registeredPlugins = [{
|
|
95
|
+
id: 'p1',
|
|
96
|
+
manifest: { buttons: [{ id: 'btn1', expandedWhen: () => true }] }
|
|
97
|
+
}]
|
|
98
|
+
|
|
99
|
+
renderHook(() => useButtonStateEvaluator((fn) => fn()))
|
|
100
|
+
expect(mockDispatch).toHaveBeenCalledWith({
|
|
101
|
+
type: 'TOGGLE_BUTTON_EXPANDED',
|
|
102
|
+
payload: { id: 'btn1', isExpanded: true }
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
92
106
|
it('does not dispatch if state already matches', () => {
|
|
93
107
|
mockAppState.disabledButtons.add('btn1')
|
|
94
108
|
mockAppState.hiddenButtons.add('btn2')
|
|
95
109
|
mockAppState.pressedButtons.add('btn3')
|
|
110
|
+
mockAppState.expandedButtons.add('btn4')
|
|
96
111
|
|
|
97
112
|
mockPluginRegistry.registeredPlugins = [
|
|
98
113
|
{ id: 'p1', manifest: { buttons: [{ id: 'btn1', enableWhen: () => false }] } },
|
|
99
114
|
{ id: 'p2', manifest: { buttons: [{ id: 'btn2', hiddenWhen: () => true }] } },
|
|
100
|
-
{ id: 'p3', manifest: { buttons: [{ id: 'btn3', pressedWhen: () => true }] } }
|
|
115
|
+
{ id: 'p3', manifest: { buttons: [{ id: 'btn3', pressedWhen: () => true }] } },
|
|
116
|
+
{ id: 'p4', manifest: { buttons: [{ id: 'btn4', expandedWhen: () => true }] } }
|
|
101
117
|
]
|
|
102
118
|
|
|
103
119
|
renderHook(() => useButtonStateEvaluator((fn) => fn()))
|
|
@@ -112,13 +128,14 @@ describe('useButtonStateEvaluator', () => {
|
|
|
112
128
|
buttons: [
|
|
113
129
|
{ id: 'btn1', enableWhen: failingFn },
|
|
114
130
|
{ id: 'btn2', hiddenWhen: failingFn },
|
|
115
|
-
{ id: 'btn3', pressedWhen: failingFn }
|
|
131
|
+
{ id: 'btn3', pressedWhen: failingFn },
|
|
132
|
+
{ id: 'btn4', expandedWhen: failingFn }
|
|
116
133
|
]
|
|
117
134
|
}
|
|
118
135
|
}]
|
|
119
136
|
|
|
120
137
|
renderHook(() => useButtonStateEvaluator((fn, pluginId) => fn(pluginId)))
|
|
121
|
-
expect(console.warn).toHaveBeenCalledTimes(
|
|
138
|
+
expect(console.warn).toHaveBeenCalledTimes(4)
|
|
122
139
|
expect(mockDispatch).not.toHaveBeenCalled()
|
|
123
140
|
})
|
|
124
141
|
|
|
@@ -130,4 +147,20 @@ describe('useButtonStateEvaluator', () => {
|
|
|
130
147
|
renderHook(() => useButtonStateEvaluator((fn) => fn({ pluginState: {} })))
|
|
131
148
|
expect(enableWhen).toHaveBeenCalled()
|
|
132
149
|
})
|
|
150
|
+
|
|
151
|
+
it('covers fallback to empty array when manifest or buttons is missing', () => {
|
|
152
|
+
// Branch 1: Plugin exists but manifest is missing
|
|
153
|
+
// Branch 2: Manifest exists but buttons is missing
|
|
154
|
+
mockPluginRegistry.registeredPlugins = [
|
|
155
|
+
{ id: 'p1' },
|
|
156
|
+
{ id: 'p2', manifest: {} },
|
|
157
|
+
{ id: 'p3', manifest: { buttons: null } }
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
renderHook(() => useButtonStateEvaluator((fn) => fn()))
|
|
161
|
+
|
|
162
|
+
// If the fallback (|| []) works, the code continues to the next plugin
|
|
163
|
+
// without throwing a "cannot read property forEach of undefined" error.
|
|
164
|
+
expect(mockDispatch).not.toHaveBeenCalled()
|
|
165
|
+
})
|
|
133
166
|
})
|
|
@@ -6,6 +6,53 @@ import { useService } from '../store/serviceContext.js'
|
|
|
6
6
|
import { scaleFactor } from '../../config/appConfig.js'
|
|
7
7
|
import { EVENTS as events } from '../../config/events.js'
|
|
8
8
|
|
|
9
|
+
const assignCrossHairAPI = (crossHair, el, mapProvider, dispatch, updatePosition) => {
|
|
10
|
+
crossHair.pinToMap = (coords, state) => {
|
|
11
|
+
const { x, y } = mapProvider.mapToScreen(coords)
|
|
12
|
+
crossHair.coords = coords
|
|
13
|
+
dispatch({ type: 'UPDATE_CROSS_HAIR', payload: { isPinnedToMap: true, isVisible: true, coords, state } })
|
|
14
|
+
updatePosition(el, x, y)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
crossHair.fixAtCenter = () => {
|
|
18
|
+
el.style.left = '50%'
|
|
19
|
+
el.style.top = '50%'
|
|
20
|
+
el.style.transform = 'translate(0,0)'
|
|
21
|
+
el.style.display = 'block'
|
|
22
|
+
dispatch({ type: 'UPDATE_CROSS_HAIR', payload: { isPinnedToMap: false, isVisible: true } })
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
crossHair.remove = () => {
|
|
26
|
+
el.style.display = 'none'
|
|
27
|
+
dispatch({ type: 'UPDATE_CROSS_HAIR', payload: { isPinnedToMap: false, isVisible: false } })
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
crossHair.show = () => {
|
|
31
|
+
el.style.display = 'block'
|
|
32
|
+
dispatch({ type: 'UPDATE_CROSS_HAIR', payload: { isVisible: true } })
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
crossHair.hide = () => {
|
|
36
|
+
el.style.display = 'none'
|
|
37
|
+
dispatch({ type: 'UPDATE_CROSS_HAIR', payload: { isVisible: false } })
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
crossHair.setStyle = (state) => {
|
|
41
|
+
dispatch({ type: 'UPDATE_CROSS_HAIR', payload: { state } })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
crossHair.getDetail = () => {
|
|
45
|
+
const coords = crossHair.isPinnedToMap ? crossHair.coords : mapProvider.getCenter()
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
state: crossHair.state,
|
|
49
|
+
point: mapProvider.mapToScreen(coords),
|
|
50
|
+
zoom: mapProvider.getZoom(),
|
|
51
|
+
coords
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
9
56
|
export const useCrossHair = () => {
|
|
10
57
|
const { mapProvider } = useConfig()
|
|
11
58
|
const { safeZoneInset } = useApp()
|
|
@@ -25,55 +72,10 @@ export const useCrossHair = () => {
|
|
|
25
72
|
|
|
26
73
|
const crossHairRef = useCallback(el => {
|
|
27
74
|
if (!el) {
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// --- API ---
|
|
32
|
-
|
|
33
|
-
crossHair.pinToMap = (coords, state) => {
|
|
34
|
-
const { x, y } = mapProvider.mapToScreen(coords)
|
|
35
|
-
crossHair.coords = coords
|
|
36
|
-
dispatch({ type: 'UPDATE_CROSS_HAIR', payload: { isPinnedToMap: true, isVisible: true, coords, state } })
|
|
37
|
-
updatePosition(el, x, y)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
crossHair.fixAtCenter = () => {
|
|
41
|
-
el.style.left = '50%'
|
|
42
|
-
el.style.top = '50%'
|
|
43
|
-
el.style.transform = 'translate(0,0)'
|
|
44
|
-
el.style.display = 'block'
|
|
45
|
-
dispatch({ type: 'UPDATE_CROSS_HAIR', payload: { isPinnedToMap: false, isVisible: true } })
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
crossHair.remove = () => {
|
|
49
|
-
el.style.display = 'none'
|
|
50
|
-
dispatch({ type: 'UPDATE_CROSS_HAIR', payload: { isPinnedToMap: false, isVisible: false } })
|
|
75
|
+
return undefined
|
|
51
76
|
}
|
|
52
77
|
|
|
53
|
-
crossHair
|
|
54
|
-
el.style.display = 'block'
|
|
55
|
-
dispatch({ type: 'UPDATE_CROSS_HAIR', payload: { isVisible: true } })
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
crossHair.hide = () => {
|
|
59
|
-
el.style.display = 'none'
|
|
60
|
-
dispatch({ type: 'UPDATE_CROSS_HAIR', payload: { isVisible: false } })
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
crossHair.setStyle = (state) => {
|
|
64
|
-
dispatch({ type: 'UPDATE_CROSS_HAIR', payload: { state } })
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
crossHair.getDetail = () => {
|
|
68
|
-
const coords = crossHair.isPinnedToMap ? crossHair.coords : mapProvider.getCenter()
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
state: crossHair.state,
|
|
72
|
-
point: mapProvider.mapToScreen(coords),
|
|
73
|
-
zoom: mapProvider.getZoom(),
|
|
74
|
-
coords
|
|
75
|
-
}
|
|
76
|
-
}
|
|
78
|
+
assignCrossHairAPI(crossHair, el, mapProvider, dispatch, updatePosition)
|
|
77
79
|
|
|
78
80
|
const handleRender = () => {
|
|
79
81
|
if (crossHair.coords && crossHair.isPinnedToMap) {
|
|
@@ -11,7 +11,7 @@ export function useFocusVisible () {
|
|
|
11
11
|
useEffect(() => {
|
|
12
12
|
const scope = layoutRefs.appContainerRef.current
|
|
13
13
|
if (!scope) {
|
|
14
|
-
return
|
|
14
|
+
return undefined
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
function handleFocusIn (e) {
|
|
@@ -22,7 +22,7 @@ export function useFocusVisible () {
|
|
|
22
22
|
delete e.target.dataset.focusVisible
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
function handlePointerdown (
|
|
25
|
+
function handlePointerdown () {
|
|
26
26
|
delete document.activeElement.dataset.focusVisible
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -5,12 +5,46 @@ import { useApp } from '../store/appContext.js'
|
|
|
5
5
|
import { useService } from '../store/serviceContext.js'
|
|
6
6
|
|
|
7
7
|
export const useInterfaceAPI = () => {
|
|
8
|
-
const { dispatch } = useApp()
|
|
8
|
+
const { dispatch, hiddenButtons, disabledButtons, pressedButtons, expandedButtons } = useApp()
|
|
9
9
|
const { eventBus } = useService()
|
|
10
10
|
|
|
11
11
|
useEffect(() => {
|
|
12
12
|
const handleAddButton = ({ id, config }) => {
|
|
13
|
+
// Add the button
|
|
13
14
|
dispatch({ type: 'ADD_BUTTON', payload: { id, config } })
|
|
15
|
+
// Add all optional menu items as individual buttons
|
|
16
|
+
if (Array.isArray(config.menuItems)) {
|
|
17
|
+
config.menuItems.forEach(item => {
|
|
18
|
+
dispatch({ type: 'ADD_BUTTON', payload: { id: item.id, config: item } })
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const handleToggleButtonState = ({ id, prop, value }) => {
|
|
24
|
+
switch (prop) {
|
|
25
|
+
case 'hidden': {
|
|
26
|
+
const isHidden = typeof value === 'boolean' ? value : !hiddenButtons.has(id)
|
|
27
|
+
dispatch({ type: 'TOGGLE_BUTTON_HIDDEN', payload: { id, isHidden } })
|
|
28
|
+
break
|
|
29
|
+
}
|
|
30
|
+
case 'disabled': {
|
|
31
|
+
const isDisabled = typeof value === 'boolean' ? value : !disabledButtons.has(id)
|
|
32
|
+
dispatch({ type: 'TOGGLE_BUTTON_DISABLED', payload: { id, isDisabled } })
|
|
33
|
+
break
|
|
34
|
+
}
|
|
35
|
+
case 'pressed': {
|
|
36
|
+
const isPressed = typeof value === 'boolean' ? value : !pressedButtons.has(id)
|
|
37
|
+
dispatch({ type: 'TOGGLE_BUTTON_PRESSED', payload: { id, isPressed } })
|
|
38
|
+
break
|
|
39
|
+
}
|
|
40
|
+
case 'expanded': {
|
|
41
|
+
const isExpanded = typeof value === 'boolean' ? value : !expandedButtons.has(id)
|
|
42
|
+
dispatch({ type: 'TOGGLE_BUTTON_EXPANDED', payload: { id, isExpanded } })
|
|
43
|
+
break
|
|
44
|
+
}
|
|
45
|
+
default:
|
|
46
|
+
break
|
|
47
|
+
}
|
|
14
48
|
}
|
|
15
49
|
|
|
16
50
|
const handleAddPanel = ({ id, config }) => {
|
|
@@ -34,6 +68,7 @@ export const useInterfaceAPI = () => {
|
|
|
34
68
|
}
|
|
35
69
|
|
|
36
70
|
eventBus.on(events.APP_ADD_BUTTON, handleAddButton)
|
|
71
|
+
eventBus.on(events.APP_TOGGLE_BUTTON_STATE, handleToggleButtonState)
|
|
37
72
|
eventBus.on(events.APP_ADD_PANEL, handleAddPanel)
|
|
38
73
|
eventBus.on(events.APP_REMOVE_PANEL, handleRemovePanel)
|
|
39
74
|
eventBus.on(events.APP_SHOW_PANEL, handleShowPanel)
|
|
@@ -13,7 +13,7 @@ export function useKeyboardShortcuts (containerRef) {
|
|
|
13
13
|
useEffect(() => {
|
|
14
14
|
const el = containerRef.current
|
|
15
15
|
if (!el || interfaceType !== 'keyboard') {
|
|
16
|
-
return
|
|
16
|
+
return undefined
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const actions = createKeyboardActions(mapProvider, announce, {
|
|
@@ -31,7 +31,7 @@ export function useKeyboardShortcuts (containerRef) {
|
|
|
31
31
|
|
|
32
32
|
// Use e.code for letters to avoid 'dead' keys with Alt/AltGr
|
|
33
33
|
if (/^Key[A-Z]$/.test(e.code)) {
|
|
34
|
-
key = e.code.slice(3) // "KeyI" -> "I"
|
|
34
|
+
key = e.code.slice(3) // NOSONAR: strip "Key" prefix, e.g. "KeyI" -> "I"
|
|
35
35
|
} else {
|
|
36
36
|
key = e.key // works for arrows, numpad, punctuation
|
|
37
37
|
}
|
|
@@ -41,6 +41,8 @@ export function useKeyboardShortcuts (containerRef) {
|
|
|
41
41
|
key = '+'
|
|
42
42
|
} else if (key === 'Subtract' || key === 'NumpadSubtract') {
|
|
43
43
|
key = '-'
|
|
44
|
+
} else {
|
|
45
|
+
// No action
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
return e.altKey ? `Alt+${key}` : key
|
|
@@ -5,6 +5,39 @@ import { useService } from '../store/serviceContext.js'
|
|
|
5
5
|
import { getMapStatusMessage } from '../../utils/getMapStatusMessage.js'
|
|
6
6
|
import { EVENTS as events } from '../../config/events.js'
|
|
7
7
|
|
|
8
|
+
const resolveMessage = (previous, current, mapProvider) => {
|
|
9
|
+
const zoomChanged = previous.zoom !== current.zoom
|
|
10
|
+
const centerChanged =
|
|
11
|
+
previous.center[0] !== current.center[0] ||
|
|
12
|
+
previous.center[1] !== current.center[1]
|
|
13
|
+
|
|
14
|
+
const areaDimensions = mapProvider.getAreaDimensions()
|
|
15
|
+
|
|
16
|
+
// Panned only
|
|
17
|
+
if (centerChanged && !zoomChanged) {
|
|
18
|
+
const direction = mapProvider.getCardinalMove(previous.center, current.center)
|
|
19
|
+
return getMapStatusMessage.moved({ direction, areaDimensions })
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Zoomed only
|
|
23
|
+
if (!centerChanged && zoomChanged) {
|
|
24
|
+
return getMapStatusMessage.zoomed({
|
|
25
|
+
...current,
|
|
26
|
+
from: previous.zoom,
|
|
27
|
+
to: current.zoom,
|
|
28
|
+
areaDimensions
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// No change
|
|
33
|
+
if (!centerChanged && !zoomChanged) {
|
|
34
|
+
return getMapStatusMessage.noChange({ ...current })
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Panned and zoomed
|
|
38
|
+
return getMapStatusMessage.newArea({ ...current, areaDimensions })
|
|
39
|
+
}
|
|
40
|
+
|
|
8
41
|
export function useMapAnnouncements () {
|
|
9
42
|
const { mapProvider } = useConfig()
|
|
10
43
|
const { eventBus, announce } = useService()
|
|
@@ -15,38 +48,7 @@ export function useMapAnnouncements () {
|
|
|
15
48
|
return
|
|
16
49
|
}
|
|
17
50
|
|
|
18
|
-
const
|
|
19
|
-
const centerChanged =
|
|
20
|
-
previous.center[0] !== current.center[0] ||
|
|
21
|
-
previous.center[1] !== current.center[1]
|
|
22
|
-
|
|
23
|
-
const areaDimensions = mapProvider.getAreaDimensions()
|
|
24
|
-
let message
|
|
25
|
-
|
|
26
|
-
if (centerChanged && !zoomChanged) {
|
|
27
|
-
const direction = mapProvider.getCardinalMove(previous.center, current.center)
|
|
28
|
-
message = getMapStatusMessage.moved({
|
|
29
|
-
direction,
|
|
30
|
-
areaDimensions
|
|
31
|
-
})
|
|
32
|
-
} else if (!centerChanged && zoomChanged) {
|
|
33
|
-
message = getMapStatusMessage.zoomed({
|
|
34
|
-
...current,
|
|
35
|
-
from: previous.zoom,
|
|
36
|
-
to: current.zoom,
|
|
37
|
-
areaDimensions
|
|
38
|
-
})
|
|
39
|
-
} else if (!centerChanged && !zoomChanged) {
|
|
40
|
-
message = getMapStatusMessage.noChange({
|
|
41
|
-
...current
|
|
42
|
-
})
|
|
43
|
-
} else {
|
|
44
|
-
message = getMapStatusMessage.newArea({
|
|
45
|
-
...current,
|
|
46
|
-
areaDimensions
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
|
|
51
|
+
const message = resolveMessage(previous, current, mapProvider)
|
|
50
52
|
if (message) {
|
|
51
53
|
announce(message, 'core')
|
|
52
54
|
}
|
|
@@ -2,13 +2,24 @@ import { useEffect } from 'react'
|
|
|
2
2
|
import { useConfig } from '../store/configContext.js'
|
|
3
3
|
import { useService } from '../store/serviceContext.js'
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Subscribes to map events via the shared event bus for the lifetime of
|
|
7
|
+
* the consuming component. Handlers are automatically unsubscribed on
|
|
8
|
+
* unmount or when the eventMap reference changes.
|
|
9
|
+
*
|
|
10
|
+
* Supported events include clicks, pans, zooms, style changes and more
|
|
11
|
+
* — see `EVENTS` in `config/events.js` for the full list.
|
|
12
|
+
*
|
|
13
|
+
* @param {Object<string, Function>} [eventMap={}] - A map of event names to
|
|
14
|
+
* callback functions.
|
|
15
|
+
*/
|
|
5
16
|
export function useMapEvents (eventMap = {}) {
|
|
6
17
|
const { mapProvider } = useConfig()
|
|
7
18
|
const { eventBus } = useService()
|
|
8
19
|
|
|
9
20
|
useEffect(() => {
|
|
10
21
|
if (!mapProvider) {
|
|
11
|
-
return
|
|
22
|
+
return undefined
|
|
12
23
|
}
|
|
13
24
|
|
|
14
25
|
const handlers = {}
|
|
@@ -32,14 +32,14 @@ export const useMapProviderOverrides = () => {
|
|
|
32
32
|
|
|
33
33
|
useEffect(() => {
|
|
34
34
|
if (!mapProvider) {
|
|
35
|
-
return
|
|
35
|
+
return undefined
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
const originalFitToBounds = mapProvider.fitToBounds
|
|
39
39
|
|
|
40
40
|
mapProvider.fitToBounds = (bounds, skipPaddingCalc = false) => {
|
|
41
41
|
if (!bounds) {
|
|
42
|
-
return
|
|
42
|
+
return undefined
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// Calculate and set safe zone padding unless explicitly skipped
|
|
@@ -54,7 +54,7 @@ export const useMapProviderOverrides = () => {
|
|
|
54
54
|
|
|
55
55
|
mapProvider.setView = ({ center, zoom }) => {
|
|
56
56
|
if (!center) {
|
|
57
|
-
return
|
|
57
|
+
return undefined
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
updatePadding()
|
|
@@ -4,6 +4,12 @@ import { useMap } from '../store/mapContext.js'
|
|
|
4
4
|
import { useService } from '../store/serviceContext.js'
|
|
5
5
|
import { EVENTS as events } from '../../config/events.js'
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Keeps React state in sync with the map provider by listening to move,
|
|
9
|
+
* move-end and first-idle events. On each move-end it also emits a
|
|
10
|
+
* MAP_STATE_UPDATED event carrying both the previous and current state,
|
|
11
|
+
* which other hooks (e.g. useMapAnnouncements) use to determine what changed.
|
|
12
|
+
*/
|
|
7
13
|
export function useMapStateSync () {
|
|
8
14
|
const { mapProvider } = useConfig()
|
|
9
15
|
const { dispatch } = useMap()
|
|
@@ -14,7 +20,7 @@ export function useMapStateSync () {
|
|
|
14
20
|
|
|
15
21
|
useEffect(() => {
|
|
16
22
|
if (!mapProvider) {
|
|
17
|
-
return
|
|
23
|
+
return undefined
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
// Handle map move
|
|
@@ -4,13 +4,18 @@ import { useConfig } from '../store/configContext.js'
|
|
|
4
4
|
import { useService } from '../store/serviceContext.js'
|
|
5
5
|
import { EVENTS as events } from '../../config/events.js'
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Persists the current map center and zoom into the page URL whenever the
|
|
9
|
+
* map state changes, allowing the view to be restored on page reload or
|
|
10
|
+
* shared via a link.
|
|
11
|
+
*/
|
|
7
12
|
export function useMapURLSync () {
|
|
8
13
|
const { id } = useConfig()
|
|
9
14
|
const { eventBus } = useService()
|
|
10
15
|
|
|
11
16
|
useEffect(() => {
|
|
12
17
|
if (!id) {
|
|
13
|
-
return
|
|
18
|
+
return undefined
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
const handleStateUpdate = ({ current }) => {
|