@defra/interactive-map 0.0.14-alpha → 0.0.16-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/assets/css/docusaurus.css +104 -0
  2. package/assets/images/favicon.svg +1 -0
  3. package/assets/images/hero.png +0 -0
  4. package/dist/css/index.css +1 -1
  5. package/dist/esm/im-core.js +1 -1
  6. package/dist/umd/im-core.js +1 -1
  7. package/dist/umd/index.js +1 -1
  8. package/docs/api/slot-map.svg +1 -0
  9. package/docs/api/slots.md +89 -6
  10. package/docs/api.md +1 -1
  11. package/docs/architecture.md +3 -1
  12. package/docs/{demo.mdx → examples.mdx} +1 -1
  13. package/docs/getting-started.md +1 -3
  14. package/docs/index.mdx +42 -0
  15. package/docs/plugins/interact.md +176 -55
  16. package/docs/plugins/map-styles.md +64 -7
  17. package/docs/plugins/search.md +207 -63
  18. package/docs/plugins.md +7 -15
  19. package/docusaurus.config.cjs +34 -34
  20. package/jest.setup.js +1 -1
  21. package/package.json +5 -4
  22. package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
  23. package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +1 -1
  24. package/plugins/beta/datasets/src/DatasetsInit.jsx +1 -1
  25. package/plugins/beta/datasets/src/api/addDataset.js +1 -1
  26. package/plugins/beta/datasets/src/api/hideDataset.js +1 -1
  27. package/plugins/beta/datasets/src/api/hideFeatures.js +1 -1
  28. package/plugins/beta/datasets/src/api/removeDataset.js +1 -1
  29. package/plugins/beta/datasets/src/api/showDataset.js +1 -1
  30. package/plugins/beta/datasets/src/api/showFeatures.js +1 -1
  31. package/plugins/beta/datasets/src/datasets.js +4 -4
  32. package/plugins/beta/datasets/src/defaults.js +1 -1
  33. package/plugins/beta/datasets/src/fetch/createDynamicSource.js +5 -5
  34. package/plugins/beta/datasets/src/handleSetMapStyle.js +1 -1
  35. package/plugins/beta/datasets/src/manifest.js +7 -7
  36. package/plugins/beta/datasets/src/mapLayers.js +2 -3
  37. package/plugins/beta/datasets/src/panels/Key.jsx +31 -29
  38. package/plugins/beta/datasets/src/panels/Layers.jsx +8 -9
  39. package/plugins/beta/datasets/src/utils/bbox.js +4 -4
  40. package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
  41. package/plugins/beta/draw-es/src/DrawInit.jsx +16 -16
  42. package/plugins/beta/draw-es/src/api/addFeature.js +3 -3
  43. package/plugins/beta/draw-es/src/api/deleteFeature.js +3 -3
  44. package/plugins/beta/draw-es/src/api/editFeature.js +3 -3
  45. package/plugins/beta/draw-es/src/api/newPolygon.js +3 -3
  46. package/plugins/beta/draw-es/src/events.js +52 -20
  47. package/plugins/beta/draw-es/src/events.test.js +301 -0
  48. package/plugins/beta/draw-es/src/graphic.js +1 -1
  49. package/plugins/beta/draw-es/src/manifest.js +4 -4
  50. package/plugins/beta/draw-es/src/reducer.js +1 -1
  51. package/plugins/beta/draw-es/src/sketchViewModel.js +1 -1
  52. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
  53. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
  54. package/plugins/beta/draw-ml/src/DrawInit.jsx +49 -52
  55. package/plugins/beta/draw-ml/src/api/deleteFeature.js +1 -1
  56. package/plugins/beta/draw-ml/src/api/editFeature.js +8 -5
  57. package/plugins/beta/draw-ml/src/api/newLine.js +0 -1
  58. package/plugins/beta/draw-ml/src/api/newPolygon.js +0 -1
  59. package/plugins/beta/draw-ml/src/api/split.js +4 -4
  60. package/plugins/beta/draw-ml/src/defaults.js +1 -1
  61. package/plugins/beta/draw-ml/src/events.js +8 -6
  62. package/plugins/beta/draw-ml/src/manifest.js +15 -15
  63. package/plugins/beta/draw-ml/src/mapboxDraw.js +1 -1
  64. package/plugins/beta/draw-ml/src/mapboxSnap.js +17 -18
  65. package/plugins/beta/draw-ml/src/modes/createDrawMode.js +31 -31
  66. package/plugins/beta/draw-ml/src/modes/disabledMode.js +1 -1
  67. package/plugins/beta/draw-ml/src/modes/editVertex/touchHandlers.js +11 -11
  68. package/plugins/beta/draw-ml/src/modes/editVertex/undoHandlers.js +7 -7
  69. package/plugins/beta/draw-ml/src/modes/editVertex/vertexOperations.js +8 -8
  70. package/plugins/beta/draw-ml/src/modes/editVertex/vertexQueries.js +7 -7
  71. package/plugins/beta/draw-ml/src/modes/editVertexMode.js +32 -24
  72. package/plugins/beta/draw-ml/src/reducer.js +1 -1
  73. package/plugins/beta/draw-ml/src/undoStack.js +4 -4
  74. package/plugins/beta/draw-ml/src/utils/snapHelpers.js +12 -12
  75. package/plugins/beta/draw-ml/src/utils/spatial.js +11 -11
  76. package/plugins/beta/frame/src/Frame.jsx +4 -4
  77. package/plugins/beta/frame/src/FrameInit.jsx +4 -4
  78. package/plugins/beta/frame/src/api/addFrame.js +1 -1
  79. package/plugins/beta/frame/src/api/editFeature.js +1 -1
  80. package/plugins/beta/frame/src/config.js +1 -1
  81. package/plugins/beta/frame/src/manifest.js +3 -3
  82. package/plugins/beta/frame/src/reducer.js +1 -1
  83. package/plugins/beta/frame/src/utils.js +1 -1
  84. package/plugins/beta/map-styles/dist/esm/im-map-styles-plugin.js +1 -1
  85. package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -1
  86. package/plugins/beta/map-styles/src/MapStyles.jsx +18 -18
  87. package/plugins/beta/map-styles/src/manifest.js +2 -2
  88. package/plugins/beta/scale-bar/src/ScaleBar.jsx +5 -5
  89. package/plugins/beta/use-location/src/UseLocation.jsx +1 -1
  90. package/plugins/beta/use-location/src/defaults.js +1 -1
  91. package/plugins/beta/use-location/src/events.js +3 -3
  92. package/plugins/interact/src/InteractInit.jsx +1 -2
  93. package/plugins/interact/src/api/enable.js +8 -5
  94. package/plugins/interact/src/api/enable.test.js +2 -2
  95. package/plugins/interact/src/api/selectFeature.js +4 -4
  96. package/plugins/interact/src/api/unselectFeature.js +5 -5
  97. package/plugins/interact/src/defaults.js +0 -1
  98. package/plugins/interact/src/events.test.js +15 -15
  99. package/plugins/interact/src/hooks/useHighlightSync.js +1 -1
  100. package/plugins/interact/src/hooks/useInteractionHandlers.js +2 -2
  101. package/plugins/interact/src/hooks/useInteractionHandlers.test.js +5 -5
  102. package/plugins/interact/src/manifest.js +2 -2
  103. package/plugins/interact/src/manifest.test.js +3 -4
  104. package/plugins/interact/src/reducer.js +3 -3
  105. package/plugins/interact/src/reducer.test.js +0 -1
  106. package/plugins/interact/src/utils/spatial.js +10 -10
  107. package/plugins/interact/src/utils/spatial.test.js +14 -14
  108. package/plugins/search/dist/css/index.css +1 -1
  109. package/plugins/search/dist/esm/im-search-plugin.js +1 -1
  110. package/plugins/search/dist/esm/index.js +1 -1
  111. package/plugins/search/dist/umd/im-search-plugin.js +1 -1
  112. package/plugins/search/dist/umd/index.js +1 -1
  113. package/plugins/search/src/Search.jsx +7 -6
  114. package/plugins/search/src/Search.test.jsx +23 -23
  115. package/plugins/search/src/components/CloseButton/CloseButton.jsx +15 -15
  116. package/plugins/search/src/components/CloseButton/CloseButton.test.jsx +2 -2
  117. package/plugins/search/src/components/Form/Form.jsx +14 -14
  118. package/plugins/search/src/components/Form/Form.test.jsx +11 -11
  119. package/plugins/search/src/components/OpenButton/OpenButton.jsx +16 -15
  120. package/plugins/search/src/components/OpenButton/OpenButton.test.jsx +6 -2
  121. package/plugins/search/src/components/SubmitButton/SubmitButton.jsx +15 -15
  122. package/plugins/search/src/components/Suggestions/Suggestions.jsx +6 -6
  123. package/plugins/search/src/components/Suggestions/Suggestions.test.jsx +4 -4
  124. package/plugins/search/src/datasets.js +12 -13
  125. package/plugins/search/src/datasets.test.js +1 -1
  126. package/plugins/search/src/defaults.js +1 -1
  127. package/plugins/search/src/events/fetchSuggestions.js +4 -4
  128. package/plugins/search/src/events/fetchSuggestions.test.js +5 -5
  129. package/plugins/search/src/events/formHandlers.js +3 -3
  130. package/plugins/search/src/events/formHandlers.test.js +1 -1
  131. package/plugins/search/src/events/index.js +2 -2
  132. package/plugins/search/src/events/index.test.js +2 -2
  133. package/plugins/search/src/events/inputHandlers.js +4 -4
  134. package/plugins/search/src/events/inputHandlers.test.js +1 -1
  135. package/plugins/search/src/events/suggestionHandlers.js +2 -2
  136. package/plugins/search/src/events/suggestionHandlers.test.js +1 -1
  137. package/plugins/search/src/index.js +2 -1
  138. package/plugins/search/src/index.test.js +3 -3
  139. package/plugins/search/src/manifest.js +6 -4
  140. package/plugins/search/src/reducer.js +1 -2
  141. package/plugins/search/src/reducer.test.js +2 -2
  142. package/plugins/search/src/search.scss +18 -6
  143. package/plugins/search/src/utils/parseOsNamesResults.js +1 -2
  144. package/plugins/search/src/utils/parseOsNamesResults.test.js +2 -2
  145. package/plugins/search/src/utils/updateMap.js +1 -1
  146. package/plugins/search/src/utils/updateMap.test.js +5 -5
  147. package/providers/beta/esri/dist/esm/im-esri-provider.js +1 -1
  148. package/providers/beta/esri/src/esriProvider.js +5 -5
  149. package/providers/beta/esri/src/utils/coords.js +1 -1
  150. package/providers/beta/esri/src/utils/esriFixes.js +1 -1
  151. package/providers/beta/esri/src/utils/query.js +4 -4
  152. package/providers/beta/esri/src/utils/spatial.js +1 -2
  153. package/providers/beta/esri/src/utils/spatial.test.js +4 -1
  154. package/providers/beta/open-names/src/utils/mapToLocationModel.test.js +1 -1
  155. package/providers/maplibre/src/appEvents.test.js +1 -1
  156. package/providers/maplibre/src/index.js +1 -1
  157. package/providers/maplibre/src/index.test.js +3 -5
  158. package/providers/maplibre/src/mapEvents.test.js +15 -5
  159. package/providers/maplibre/src/maplibreProvider.test.js +6 -2
  160. package/providers/maplibre/src/utils/calculateLinearTextSize.js +4 -4
  161. package/providers/maplibre/src/utils/calculateLinearTextSize.test.js +3 -3
  162. package/providers/maplibre/src/utils/detectWebgl.test.js +1 -1
  163. package/providers/maplibre/src/utils/highlightFeatures.js +2 -2
  164. package/providers/maplibre/src/utils/highlightFeatures.test.js +12 -6
  165. package/providers/maplibre/src/utils/labels.js +19 -20
  166. package/providers/maplibre/src/utils/labels.test.js +15 -13
  167. package/providers/maplibre/src/utils/maplibreFixes.test.js +1 -1
  168. package/providers/maplibre/src/utils/queryFeatures.js +6 -6
  169. package/providers/maplibre/src/utils/queryFeatures.test.js +13 -13
  170. package/providers/maplibre/src/utils/spatial.js +0 -1
  171. package/providers/maplibre/src/utils/spatial.test.js +26 -27
  172. package/src/App/components/Panel/Panel.module.scss +1 -0
  173. package/src/App/hooks/useLayoutMeasurements.js +1 -10
  174. package/src/App/hooks/useLayoutMeasurements.test.js +2 -5
  175. package/src/App/hooks/useVisibleGeometry.js +7 -13
  176. package/src/App/hooks/useVisibleGeometry.test.js +72 -47
  177. package/src/App/layout/Layout.jsx +0 -3
  178. package/src/App/layout/Layout.test.jsx +0 -1
  179. package/src/App/layout/layout.module.scss +11 -77
  180. package/src/App/registry/pluginRegistry.js +17 -0
  181. package/src/App/registry/pluginRegistry.test.js +33 -0
  182. package/src/App/renderer/HtmlElementHost.jsx +0 -1
  183. package/src/App/renderer/HtmlElementHost.test.jsx +20 -11
  184. package/src/App/renderer/mapButtons.js +3 -2
  185. package/src/App/renderer/mapPanels.test.js +3 -3
  186. package/src/App/renderer/slotHelpers.js +2 -2
  187. package/src/App/renderer/slotHelpers.test.js +3 -3
  188. package/src/App/renderer/slots.js +0 -3
  189. package/src/App/store/AppProvider.jsx +0 -1
  190. package/src/App/store/appDispatchMiddleware.js +33 -1
  191. package/src/App/store/appDispatchMiddleware.test.js +250 -222
  192. package/src/config/appConfig.js +4 -4
  193. package/src/utils/getSafeZoneInset.js +139 -42
  194. package/src/utils/getSafeZoneInset.test.js +298 -122
  195. package/src/utils/logger.js +6 -0
  196. package/src/utils/logger.test.js +32 -0
  197. package/webpack.dev.mjs +22 -18
  198. package/docs/govuk-prototype.md +0 -23
  199. package/docs/index.md +0 -19
@@ -10,11 +10,11 @@ describe('updateMap', () => {
10
10
 
11
11
  beforeEach(() => {
12
12
  mapProvider = {
13
- fitToBounds: jest.fn(),
13
+ fitToBounds: jest.fn()
14
14
  }
15
15
 
16
16
  markers = {
17
- add: jest.fn(),
17
+ add: jest.fn()
18
18
  }
19
19
  })
20
20
 
@@ -25,7 +25,7 @@ describe('updateMap', () => {
25
25
  point,
26
26
  markers,
27
27
  showMarker: true,
28
- markerColor: 'red',
28
+ markerColor: 'red'
29
29
  })
30
30
 
31
31
  expect(mapProvider.fitToBounds).toHaveBeenCalledWith(bounds)
@@ -43,10 +43,10 @@ describe('updateMap', () => {
43
43
  point,
44
44
  markers,
45
45
  showMarker: false,
46
- markerColor: 'blue',
46
+ markerColor: 'blue'
47
47
  })
48
48
 
49
49
  expect(mapProvider.fitToBounds).toHaveBeenCalledWith(bounds)
50
50
  expect(markers.add).not.toHaveBeenCalled()
51
51
  })
52
- })
52
+ })
@@ -1 +1 @@
1
- import e from"@babel/runtime/helpers/defineProperty";import t from"@babel/runtime/helpers/objectWithoutProperties";import r from"@babel/runtime/helpers/asyncToGenerator";import n from"@arcgis/core/config.js";import o from"@arcgis/core/layers/support/TileInfo.js";import i from"@arcgis/core/Map.js";import a from"@arcgis/core/views/MapView.js";import s from"@arcgis/core/layers/VectorTileLayer.js";import m from"@arcgis/core/geometry/Point.js";import{when as l,once as u,watch as c}from"@arcgis/core/core/reactiveUtils.js";import p from"@arcgis/core/geometry/Extent.js";var v={animationDuration:200},y=["showKeyboardHelp","selectControl","moveLarge","nudgeMap","zoomLarge","nudgeZoom"];var h=(e,t)=>{var r=null,n=function(){for(var n=arguments.length,o=new Array(n),i=0;i<n;i++)o[i]=arguments[i];clearTimeout(r),r=setTimeout(()=>{e(...o)},t)};return n.cancel=()=>{r&&(clearTimeout(r),r=null)},n};function d(e){var{mapProvider:t,view:r,baseTileLayer:n,events:o,eventBus:i,getZoom:a,getCenter:s,getBounds:m,getResolution:p}=e,v=!1,y=[],d=[],f=e=>{var t=(()=>{if(v||!r||r.destroyed||!r.extent)return null;var{maxZoom:e,minZoom:t}=r.constraints;return{center:s(),bounds:m(),resolution:p(),zoom:a(),isAtMaxZoom:r.zoom+.01>=e,isAtMinZoom:r.zoom-.01<=t}})();t&&i.emit(e,t)};l(()=>n.loaded&&r.resolution>0,()=>f(o.MAP_LOADED)),u(()=>r.ready).then(()=>{v||i.emit(o.MAP_READY,{map:t.map,view:t.view,mapStyleId:t.mapStyleId,mapSize:t.mapSize,crs:t.crs})}),u(()=>r.stationary).then(()=>f(o.MAP_FIRST_IDLE));var g=h(()=>f(o.MAP_MOVE_END),500);d.push(g),y.push(c(()=>[r.interacting,r.animation],e=>{var[t,r]=e;(t||r)&&i.emit(o.MAP_MOVE_START),t||r||g()}));var x,w,b,M=(x=()=>f(o.MAP_MOVE),w=10,b=0,function(){var e=Date.now();e-b>=w&&(b=e,x(...arguments))});d.push(M),y.push(c(()=>r.zoom,M)),y.push(c(()=>r.extent,()=>i.emit(o.MAP_RENDER),{initial:!1}));var E=h(()=>f(o.MAP_DATA_CHANGE),500);d.push(E),y.push(c(()=>r.updating,e=>!e&&E()));var A=null,S=null;return y.push(r.on("pointer-down",e=>{A=e.x,S=e.y})),y.push(r.on("pointer-up",e=>{var n;if(0===e.button&&!(Math.hypot(e.x-A,e.y-S)>6)&&"active"!==(null===(n=t.sketchViewModel)||void 0===n?void 0:n.state)){var a={x:e.x,y:e.y},s=r.toMap(a);s&&i.emit(o.MAP_CLICK,{point:a,coords:[s.x,s.y]})}})),{remove(){v=!0,d.forEach(e=>e.cancel()),y.forEach(e=>e.remove())}}}var f=e=>e?new p({xmin:e[0],ymin:e[1],xmax:e[2],ymax:e[3],spatialReference:{wkid:27700}}):void 0,g=e=>e?new m({x:e[0],y:e[1],spatialReference:{wkid:27700}}):void 0,x=(e,t)=>{if(e)if("FeatureCollection"===e.type)e.features.forEach(e=>x(e,t));else if("Feature"===e.type)x(e.geometry,t);else if("GeometryCollection"===e.type)e.geometries.forEach(e=>x(e,t));else{var r=e=>{Array.isArray(e)&&("number"==typeof e[0]?t.push(e):e.forEach(r))};r(e.coordinates)}},w=e=>{var t=[];x(e,t);var r=t.map(e=>e[0]),n=t.map(e=>e[1]);return f([Math.min(...r),Math.min(...n),Math.max(...r),Math.max(...n)])},b=e=>{var t=1609.344,r=e/t;if(r<.5/t)return"".concat(Math.round(e),"m");if(r<10){var n=Number.parseFloat(r.toFixed(1)),o=1===n?"mile":"miles";return"".concat(n," ").concat(o)}var i=Math.round(r),a=1===i?"mile":"miles";return"".concat(i," ").concat(a)};var M={top:0,right:0,bottom:0,left:0};function E(){return(E=r(function*(e,t){if(!e||!t)return[];var r=e.map.layers.filter(e=>e instanceof s);return r.length?(yield e.hitTest(t,{include:r.toArray()})).results.map(e=>({layerId:e.layer.id,layerTitle:e.layer.title||e.layer.id,type:e.layer.type,geometry:e.graphic.geometry,symbol:e.graphic.symbol})):[]})).apply(this,arguments)}var A=["container","padding","mapStyle","mapSize","maxExtent"];function S(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,n)}return r}function T(t){for(var r=1;r<arguments.length;r++){var n=null!=arguments[r]?arguments[r]:{};r%2?S(Object(n),!0).forEach(function(r){e(t,r,n[r])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):S(Object(n)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))})}return t}class P{constructor(e){var{mapProviderConfig:t={},events:r,eventBus:n}=e;this.events=r,this.eventBus=n,this.capabilities={supportedShortcuts:y,supportsMapSizes:!1},Object.assign(this,t),this.mapEventHandles=[],this.appEventHandles=[]}initMap(e){var m=this;return r(function*(){var{container:r,padding:l,mapStyle:u,mapSize:c,maxExtent:p}=e;t(e,A),m.mapStyleId=null==u?void 0:u.id,m.mapSize=c;var{events:v,eventBus:y}=m;m.setupConfig&&(yield m.setupConfig(n));var h=new s({id:"baselayer",url:u.url,visible:!0}),x=new i({layers:[h]}),w=p?f(p):null,b=new a({spatialReference:27700,container:r,map:x,zoom:e.zoom,center:g(e.center),maxExtent:p,constraints:{lods:o.create({spatialReference:{wkid:27700}}).lods,snapToZoom:!1,minZoom:e.minZoom,maxZoom:e.maxZoom,maxScale:0,geometry:w,rotationEnabled:!1},ui:{components:[]},popupEnabled:!1});(e=>{if(e){var t=e.querySelector(".esri-view-surface");t.removeAttribute("role"),t.tabIndex=-1,t.style["outline-color"]="transparent",t.style.touchAction="none"}})(b.container),b.padding=l,e.bounds&&b.when(()=>b.goTo(f(e.bounds),{duration:0})),m.mapEventHandles=d({mapProvider:m,view:b,baseTileLayer:h,events:v,eventBus:y,getZoom:m.getZoom.bind(m),getCenter:m.getCenter.bind(m),getBounds:m.getBounds.bind(m),getResolution:m.getResolution.bind(m)}),m.appEventHandles=function(e){var{baseTileLayer:t,events:r,eventBus:n}=e,o=e=>{t.loadStyle(e.url).then(()=>{n.emit(r.MAP_STYLE_CHANGE,{mapStyleId:e.id})})};return n.on(r.MAP_SET_STYLE,o),{remove(){n.off(r.MAP_SET_STYLE,o)}}}({baseTileLayer:h,events:v,eventBus:y})||[],m.map=x,m.view=b,m.baseTileLayer=h})()}destroyMap(){var e,t;null===(e=this.mapEvents)||void 0===e||e.remove(),null===(t=this.appEvents)||void 0===t||t.remove(),this.mapEvents=null,this.appEvents=null,this.view&&(this.view.container=null,this.view.destroy(),this.view=null),this.map&&(this.map.removeAll(),this.map=null)}setView(e){var t,{center:r,zoom:n}=e;null===(t=this.view.animation)||void 0===t||t.destroy();var o={center:r?new m({x:r[0],y:r[1],spatialReference:{wkid:27700}}):this.view.center,zoom:null!=n?n:this.view.zoom};this.view.goTo(T(T({},o),{},{duration:v.animationDuration}))}zoomIn(e){var t;null===(t=this.view.animation)||void 0===t||t.destroy(),this.view.goTo({zoom:this.view.zoom+e,duration:v.animationDuration})}zoomOut(e){var t;null===(t=this.view.animation)||void 0===t||t.destroy(),this.view.goTo({zoom:this.view.zoom-e,duration:v.animationDuration})}panBy(e){var{x:t,y:r}=this.view.toScreen(this.view.center),n={x:t+e[0],y:r+e[1]},o=this.view.toMap(n);this.view.goTo({center:o,duration:v.animationDuration})}fitToBounds(e){var t=Array.isArray(e)?f(e):w(e);this.view.goTo(t,{duration:v.DELAY})}setPadding(e){this.view.padding=e}getCenter(){var e=this.view.center;return[e.x,e.y].map(e=>Math.round(100*e)/100)}getZoom(){return this.view.zoom}getBounds(){var{xmin:e,ymin:t,xmax:r,ymax:n}=this.view.extent;return[e,t,r,n].map(e=>Math.round(100*e)/100)}getFeaturesAtPoint(e,t){return function(e,t){return E.apply(this,arguments)}(this.view,e)}getAreaDimensions(){return(e=>{if(!(e&&e instanceof p))return"";var t=e.xmin,r=e.ymin,n=e.xmax,o=e.ymax-r,i=b(n-t),a=b(o);return"".concat(a," by ").concat(i)})(function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:M;if(!e.container)return null;var{width:r,height:n}=e.container.getBoundingClientRect(),o={x:t.left,y:n-t.bottom},i={x:r-t.right,y:t.top},a=e.toMap(o),s=e.toMap(i);return new p({xmin:a.x,ymin:a.y,xmax:s.x,ymax:s.y,spatialReference:a.spatialReference})}(this.view))}getCardinalMove(e,t){return function(e,t){var[r,n]=e,[o,i]=t,a=o-r,s=i-n,m=[];return Math.abs(s)>.1&&m.push("".concat(s>0?"north":"south"," ").concat(b(Math.abs(s)))),Math.abs(a)>.1&&m.push("".concat(a>0?"east":"west"," ").concat(b(Math.abs(a)))),m.join(", ")}(e,t)}getResolution(){return this.view.resolution}mapToScreen(e){var t=g(e),r=this.view.toScreen(t);return{x:r.x,y:r.y}}screenToMap(e){var t=this.view.toMap(e);return[t.x,t.y]}isGeometryObscured(e,t){return((e,t,r)=>{if(null==r||!r.container)return!1;var n=r.container.getBoundingClientRect(),o=w(e),i=[r.toScreen(new m({x:o.xmin,y:o.ymin,spatialReference:o.spatialReference})),r.toScreen(new m({x:o.xmin,y:o.ymax,spatialReference:o.spatialReference})),r.toScreen(new m({x:o.xmax,y:o.ymin,spatialReference:o.spatialReference})),r.toScreen(new m({x:o.xmax,y:o.ymax,spatialReference:o.spatialReference}))],a=Math.min(...i.map(e=>e.x)),s=Math.max(...i.map(e=>e.x)),l=Math.min(...i.map(e=>e.y)),u=Math.max(...i.map(e=>e.y)),c=t.left-n.left,p=t.top-n.top,v=t.right-n.left,y=t.bottom-n.top;return a<v&&s>c&&l<y&&u>p})(e,t,this.view)}}export{P as default};
1
+ import e from"@babel/runtime/helpers/defineProperty";import t from"@babel/runtime/helpers/asyncToGenerator";import r from"@arcgis/core/config.js";import n from"@arcgis/core/layers/support/TileInfo.js";import o from"@arcgis/core/Map.js";import i from"@arcgis/core/views/MapView.js";import a from"@arcgis/core/layers/VectorTileLayer.js";import s from"@arcgis/core/geometry/Point.js";import{when as m,once as l,watch as u}from"@arcgis/core/core/reactiveUtils.js";import c from"@arcgis/core/geometry/Extent.js";var p={animationDuration:200},v=["showKeyboardHelp","selectControl","moveLarge","nudgeMap","zoomLarge","nudgeZoom"];var y=(e,t)=>{var r=null,n=function(){for(var n=arguments.length,o=new Array(n),i=0;i<n;i++)o[i]=arguments[i];clearTimeout(r),r=setTimeout(()=>{e(...o)},t)};return n.cancel=()=>{r&&(clearTimeout(r),r=null)},n};function h(e){var{mapProvider:t,view:r,baseTileLayer:n,events:o,eventBus:i,getZoom:a,getCenter:s,getBounds:c,getResolution:p}=e,v=!1,h=[],d=[],f=e=>{var t=(()=>{if(v||!r||r.destroyed||!r.extent)return null;var{maxZoom:e,minZoom:t}=r.constraints;return{center:s(),bounds:c(),resolution:p(),zoom:a(),isAtMaxZoom:r.zoom+.01>=e,isAtMinZoom:r.zoom-.01<=t}})();t&&i.emit(e,t)};m(()=>n.loaded&&r.resolution>0,()=>f(o.MAP_LOADED)),l(()=>r.ready).then(()=>{v||i.emit(o.MAP_READY,{map:t.map,view:t.view,mapStyleId:t.mapStyleId,mapSize:t.mapSize,crs:t.crs})}),l(()=>r.stationary).then(()=>f(o.MAP_FIRST_IDLE));var g=y(()=>f(o.MAP_MOVE_END),500);d.push(g),h.push(u(()=>[r.interacting,r.animation],e=>{var[t,r]=e;(t||r)&&i.emit(o.MAP_MOVE_START),t||r||g()}));var w,x,b,M=(w=()=>f(o.MAP_MOVE),x=10,b=0,function(){var e=Date.now();e-b>=x&&(b=e,w(...arguments))});d.push(M),h.push(u(()=>r.zoom,M)),h.push(u(()=>r.extent,()=>i.emit(o.MAP_RENDER),{initial:!1}));var E=y(()=>f(o.MAP_DATA_CHANGE),500);d.push(E),h.push(u(()=>r.updating,e=>!e&&E()));var A=null,T=null;return h.push(r.on("pointer-down",e=>{A=e.x,T=e.y})),h.push(r.on("pointer-up",e=>{var n;if(0===e.button&&!(Math.hypot(e.x-A,e.y-T)>6)&&"active"!==(null===(n=t.sketchViewModel)||void 0===n?void 0:n.state)){var a={x:e.x,y:e.y},s=r.toMap(a);s&&i.emit(o.MAP_CLICK,{point:a,coords:[s.x,s.y]})}})),{remove(){v=!0,d.forEach(e=>e.cancel()),h.forEach(e=>e.remove())}}}var d=e=>e?new c({xmin:e[0],ymin:e[1],xmax:e[2],ymax:e[3],spatialReference:{wkid:27700}}):void 0,f=e=>e?new s({x:e[0],y:e[1],spatialReference:{wkid:27700}}):void 0,g=(e,t)=>{if(e)if("FeatureCollection"===e.type)e.features.forEach(e=>g(e,t));else if("Feature"===e.type)g(e.geometry,t);else if("GeometryCollection"===e.type)e.geometries.forEach(e=>g(e,t));else{var r=e=>{Array.isArray(e)&&("number"==typeof e[0]?t.push(e):e.forEach(r))};r(e.coordinates)}},w=e=>{var t=[];g(e,t);var r=t.map(e=>e[0]),n=t.map(e=>e[1]);return d([Math.min(...r),Math.min(...n),Math.max(...r),Math.max(...n)])},x=e=>{var t=1609.344,r=e/t;if(r<.5/t)return"".concat(Math.round(e),"m");if(r<10){var n=Number.parseFloat(r.toFixed(1)),o=1===n?"mile":"miles";return"".concat(n," ").concat(o)}var i=Math.round(r),a=1===i?"mile":"miles";return"".concat(i," ").concat(a)};var b={top:0,right:0,bottom:0,left:0};function M(){return(M=t(function*(e,t){if(!e||!t)return[];var r=e.map.layers.filter(e=>e instanceof a);return r.length?(yield e.hitTest(t,{include:r.toArray()})).results.map(e=>({layerId:e.layer.id,layerTitle:e.layer.title||e.layer.id,type:e.layer.type,geometry:e.graphic.geometry,symbol:e.graphic.symbol})):[]})).apply(this,arguments)}function E(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,n)}return r}function A(t){for(var r=1;r<arguments.length;r++){var n=null!=arguments[r]?arguments[r]:{};r%2?E(Object(n),!0).forEach(function(r){e(t,r,n[r])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):E(Object(n)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))})}return t}class T{constructor(e){var{mapProviderConfig:t={},events:r,eventBus:n}=e;this.events=r,this.eventBus=n,this.capabilities={supportedShortcuts:v,supportsMapSizes:!1},Object.assign(this,t),this.mapEventHandles=[],this.appEventHandles=[]}initMap(e){var s=this;return t(function*(){var{container:t,padding:m,mapStyle:l,mapSize:u,maxExtent:c}=e;s.mapStyleId=null==l?void 0:l.id,s.mapSize=u;var{events:p,eventBus:v}=s;s.setupConfig&&(yield s.setupConfig(r));var y=new a({id:"baselayer",url:l.url,visible:!0}),g=new o({layers:[y]}),w=c?d(c):null,x=new i({spatialReference:27700,container:t,map:g,zoom:e.zoom,center:f(e.center),maxExtent:c,constraints:{lods:n.create({spatialReference:{wkid:27700}}).lods,snapToZoom:!1,minZoom:e.minZoom,maxZoom:e.maxZoom,maxScale:0,geometry:w,rotationEnabled:!1},ui:{components:[]},popupEnabled:!1});(e=>{if(e){var t=e.querySelector(".esri-view-surface");t.removeAttribute("role"),t.tabIndex=-1,t.style["outline-color"]="transparent",t.style.touchAction="none"}})(x.container),x.padding=m,e.bounds&&x.when(()=>x.goTo(d(e.bounds),{duration:0})),s.mapEventHandles=h({mapProvider:s,view:x,baseTileLayer:y,events:p,eventBus:v,getZoom:s.getZoom.bind(s),getCenter:s.getCenter.bind(s),getBounds:s.getBounds.bind(s),getResolution:s.getResolution.bind(s)}),s.appEventHandles=function(e){var{baseTileLayer:t,events:r,eventBus:n}=e,o=e=>{t.loadStyle(e.url).then(()=>{n.emit(r.MAP_STYLE_CHANGE,{mapStyleId:e.id})})};return n.on(r.MAP_SET_STYLE,o),{remove(){n.off(r.MAP_SET_STYLE,o)}}}({baseTileLayer:y,events:p,eventBus:v})||[],s.map=g,s.view=x,s.baseTileLayer=y})()}destroyMap(){var e,t;null===(e=this.mapEvents)||void 0===e||e.remove(),null===(t=this.appEvents)||void 0===t||t.remove(),this.mapEvents=null,this.appEvents=null,this.view&&(this.view.container=null,this.view.destroy(),this.view=null),this.map&&(this.map.removeAll(),this.map=null)}setView(e){var t,{center:r,zoom:n}=e;null===(t=this.view.animation)||void 0===t||t.destroy();var o={center:r?new s({x:r[0],y:r[1],spatialReference:{wkid:27700}}):this.view.center,zoom:null!=n?n:this.view.zoom};this.view.goTo(A(A({},o),{},{duration:p.animationDuration}))}zoomIn(e){var t;null===(t=this.view.animation)||void 0===t||t.destroy(),this.view.goTo({zoom:this.view.zoom+e,duration:p.animationDuration})}zoomOut(e){var t;null===(t=this.view.animation)||void 0===t||t.destroy(),this.view.goTo({zoom:this.view.zoom-e,duration:p.animationDuration})}panBy(e){var{x:t,y:r}=this.view.toScreen(this.view.center),n={x:t+e[0],y:r+e[1]},o=this.view.toMap(n);this.view.goTo({center:o,duration:p.animationDuration})}fitToBounds(e){var t=Array.isArray(e)?d(e):w(e);this.view.goTo(t,{duration:p.DELAY})}setPadding(e){this.view.padding=e}getCenter(){var e=this.view.center;return[e.x,e.y].map(e=>Math.round(100*e)/100)}getZoom(){return this.view.zoom}getBounds(){var{xmin:e,ymin:t,xmax:r,ymax:n}=this.view.extent;return[e,t,r,n].map(e=>Math.round(100*e)/100)}getFeaturesAtPoint(e,t){return function(e,t){return M.apply(this,arguments)}(this.view,e)}getAreaDimensions(){return(e=>{if(!(e&&e instanceof c))return"";var t=e.xmin,r=e.ymin,n=e.xmax,o=e.ymax-r,i=x(n-t),a=x(o);return"".concat(a," by ").concat(i)})(function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:b;if(!e.container)return null;var{width:r,height:n}=e.container.getBoundingClientRect(),o={x:t.left,y:n-t.bottom},i={x:r-t.right,y:t.top},a=e.toMap(o),s=e.toMap(i);return new c({xmin:a.x,ymin:a.y,xmax:s.x,ymax:s.y,spatialReference:a.spatialReference})}(this.view))}getCardinalMove(e,t){return function(e,t){var[r,n]=e,[o,i]=t,a=o-r,s=i-n,m=[];return Math.abs(s)>.1&&m.push("".concat(s>0?"north":"south"," ").concat(x(Math.abs(s)))),Math.abs(a)>.1&&m.push("".concat(a>0?"east":"west"," ").concat(x(Math.abs(a)))),m.join(", ")}(e,t)}getResolution(){return this.view.resolution}mapToScreen(e){var t=f(e),r=this.view.toScreen(t);return{x:r.x,y:r.y}}screenToMap(e){var t=this.view.toMap(e);return[t.x,t.y]}isGeometryObscured(e,t){return((e,t,r)=>{if(null==r||!r.container)return!1;var n=r.container.getBoundingClientRect(),o=w(e),i=[r.toScreen(new s({x:o.xmin,y:o.ymin,spatialReference:o.spatialReference})),r.toScreen(new s({x:o.xmin,y:o.ymax,spatialReference:o.spatialReference})),r.toScreen(new s({x:o.xmax,y:o.ymin,spatialReference:o.spatialReference})),r.toScreen(new s({x:o.xmax,y:o.ymax,spatialReference:o.spatialReference}))],a=Math.min(...i.map(e=>e.x)),m=Math.max(...i.map(e=>e.x)),l=Math.min(...i.map(e=>e.y)),u=Math.max(...i.map(e=>e.y)),c=t.left-n.left,p=t.top-n.top,v=t.right-n.left,y=t.bottom-n.top;return a<v&&m>c&&l<y&&u>p})(e,t,this.view)}}export{T as default};
@@ -30,7 +30,7 @@ export default class EsriProvider {
30
30
  }
31
31
 
32
32
  async initMap (config) {
33
- const { container, padding, mapStyle, mapSize, maxExtent, ...initConfig } = config
33
+ const { container, padding, mapStyle, mapSize, maxExtent } = config
34
34
  this.mapStyleId = mapStyle?.id
35
35
  this.mapSize = mapSize
36
36
  const { events, eventBus } = this
@@ -49,7 +49,7 @@ export default class EsriProvider {
49
49
  map,
50
50
  zoom: config.zoom,
51
51
  center: getPointFromFlatCoords(config.center),
52
- maxExtent: maxExtent,
52
+ maxExtent,
53
53
  constraints: {
54
54
  lods: TileInfo.create({ spatialReference: { wkid: 27700 } }).lods,
55
55
  snapToZoom: false,
@@ -121,9 +121,9 @@ export default class EsriProvider {
121
121
  // Side-effects
122
122
  // ==========================
123
123
 
124
- setView({ center, zoom }) {
124
+ setView ({ center, zoom }) {
125
125
  this.view.animation?.destroy()
126
- const point = center ? new Point({ x: center[0], y: center[1], spatialReference: { wkid: 27700 }}) : this.view.center
126
+ const point = center ? new Point({ x: center[0], y: center[1], spatialReference: { wkid: 27700 } }) : this.view.center
127
127
  const target = { center: point, zoom: zoom ?? this.view.zoom }
128
128
  this.view.goTo({ ...target, duration: defaults.animationDuration })
129
129
  }
@@ -185,7 +185,7 @@ export default class EsriProvider {
185
185
  // ==========================
186
186
  // Spatial helpers
187
187
  // ==========================
188
-
188
+
189
189
  getAreaDimensions () {
190
190
  return getAreaDimensions(getPaddedExtent(this.view))
191
191
  }
@@ -59,4 +59,4 @@ export {
59
59
  getExtentFromFlatCoords,
60
60
  getPointFromFlatCoords,
61
61
  getBboxFromGeoJSON
62
- }
62
+ }
@@ -7,4 +7,4 @@ export const cleanDOM = (container) => {
7
7
  canvasContainer.tabIndex = -1
8
8
  canvasContainer.style['outline-color'] = 'transparent'
9
9
  canvasContainer.style.touchAction = 'none'
10
- }
10
+ }
@@ -6,7 +6,7 @@ import VectorTileLayer from '@arcgis/core/layers/VectorTileLayer.js'
6
6
  * @param {{x: number, y: number}} screenPoint - pixel coordinates relative to the view container
7
7
  * @returns {Promise<Array>} Array of objects with info about each vector tile layer hit
8
8
  */
9
- export async function queryVectorTileFeatures(view, screenPoint) {
9
+ export async function queryVectorTileFeatures (view, screenPoint) {
10
10
  if (!view || !screenPoint) {
11
11
  return []
12
12
  }
@@ -27,9 +27,9 @@ export async function queryVectorTileFeatures(view, screenPoint) {
27
27
  return hitResults.results.map(result => ({
28
28
  layerId: result.layer.id,
29
29
  layerTitle: result.layer.title || result.layer.id,
30
- type: result.layer.type, // 'vectortile'
30
+ type: result.layer.type, // 'vectortile'
31
31
  geometry: result.graphic.geometry, // usually a point representing the symbol
32
- symbol: result.graphic.symbol // symbol info (color, style, etc.)
32
+ symbol: result.graphic.symbol // symbol info (color, style, etc.)
33
33
  // Note: feature attributes are not exposed by the Esri SDK
34
34
  }))
35
- }
35
+ }
@@ -69,7 +69,7 @@ const getAreaDimensions = (extent) => {
69
69
  * @param {number[]} to - [easting, northing]
70
70
  * @returns {string}
71
71
  */
72
- function getCardinalMove(from, to) {
72
+ function getCardinalMove (from, to) {
73
73
  const [x1, y1] = from
74
74
  const [x2, y2] = to
75
75
 
@@ -125,7 +125,6 @@ const getPaddedExtent = (view, padding = DEFAULT_PADDING) => {
125
125
  })
126
126
  }
127
127
 
128
-
129
128
  /**
130
129
  * Returns true if the geometry's screen bounding box overlaps the given panel rectangle.
131
130
  * Used to decide whether to pan/zoom when a panel opens over a visibleGeometry target.
@@ -10,7 +10,10 @@ jest.mock('@arcgis/core/geometry/Point.js', () =>
10
10
 
11
11
  jest.mock('./coords.js', () => ({
12
12
  getBboxFromGeoJSON: jest.fn(() => ({
13
- xmin: 100, ymin: 200, xmax: 500, ymax: 600,
13
+ xmin: 100,
14
+ ymin: 200,
15
+ xmax: 500,
16
+ ymax: 600,
14
17
  spatialReference: { wkid: 27700 },
15
18
  type: 'extent'
16
19
  }))
@@ -58,4 +58,4 @@ describe('mapToLocationModel', () => {
58
58
  coordinates: [0, 0]
59
59
  })
60
60
  })
61
- })
61
+ })
@@ -50,4 +50,4 @@ describe('attachAppEvents', () => {
50
50
  expect(eventBus.off).toHaveBeenCalledWith(events.MAP_SET_STYLE, styleHandler)
51
51
  expect(eventBus.off).toHaveBeenCalledWith(events.MAP_SET_PIXEL_RATIO, pixelHandler)
52
52
  })
53
- })
53
+ })
@@ -14,7 +14,7 @@ import { getWebGL } from './utils/detectWebgl.js'
14
14
  *
15
15
  * @returns {boolean} true if modern syntax is supported, false otherwise
16
16
  */
17
- function supportsModernMaplibre() {
17
+ function supportsModernMaplibre () {
18
18
  return typeof ''.replaceAll === 'function'
19
19
  }
20
20
 
@@ -6,12 +6,8 @@ jest.mock('maplibre-gl', () => ({ VERSION: '3.x' }))
6
6
  jest.mock('./maplibreProvider.js', () => ({ default: class MockProvider {} }))
7
7
 
8
8
  describe('createMapLibreProvider', () => {
9
-
10
9
  beforeEach(() => {
11
10
  getWebGL.mockReturnValue({ isEnabled: true, error: null })
12
-
13
- // Ensure modern support by default
14
- String.prototype.replaceAll = jest.fn()
15
11
  })
16
12
 
17
13
  afterEach(() => {
@@ -53,11 +49,13 @@ describe('createMapLibreProvider', () => {
53
49
  })
54
50
 
55
51
  test('checkDeviceCapabilities: no replaceAll support → isSupported false', () => {
52
+ const restoreReplaceAll = String.prototype.replaceAll
56
53
  delete String.prototype.replaceAll
57
54
 
58
55
  const result = createMapLibreProvider().checkDeviceCapabilities()
59
56
 
60
57
  expect(result.isSupported).toBe(false)
58
+ String.prototype.replaceAll = restoreReplaceAll // eslint-disable-line
61
59
  })
62
60
 
63
61
  test('load returns MapProvider, mapFramework, and merged mapProviderConfig', async () => {
@@ -76,4 +74,4 @@ describe('createMapLibreProvider', () => {
76
74
 
77
75
  expect(mapProviderConfig).toEqual({ crs: 'EPSG:4326' })
78
76
  })
79
- })
77
+ })
@@ -31,9 +31,15 @@ describe('attachMapEvents', () => {
31
31
  }
32
32
  eventBus = { emit: jest.fn() }
33
33
  events = {
34
- MAP_LOADED: 'loaded', MAP_FIRST_IDLE: 'firstIdle', MAP_MOVE_START: 'moveStart',
35
- MAP_MOVE_END: 'moveEnd', MAP_MOVE: 'move', MAP_RENDER: 'render',
36
- MAP_DATA_CHANGE: 'dataChange', MAP_STYLE_CHANGE: 'styleChange', MAP_CLICK: 'click'
34
+ MAP_LOADED: 'loaded',
35
+ MAP_FIRST_IDLE: 'firstIdle',
36
+ MAP_MOVE_START: 'moveStart',
37
+ MAP_MOVE_END: 'moveEnd',
38
+ MAP_MOVE: 'move',
39
+ MAP_RENDER: 'render',
40
+ MAP_DATA_CHANGE: 'dataChange',
41
+ MAP_STYLE_CHANGE: 'styleChange',
42
+ MAP_CLICK: 'click'
37
43
  }
38
44
  getCenter = jest.fn(() => [0, 0])
39
45
  getZoom = jest.fn(() => 10)
@@ -62,8 +68,12 @@ describe('attachMapEvents', () => {
62
68
 
63
69
  test('stateful events emit map state', () => {
64
70
  const state = {
65
- center: [0, 0], bounds: [[0, 0], [1, 1]], resolution: 100,
66
- zoom: 10, isAtMaxZoom: false, isAtMinZoom: false
71
+ center: [0, 0],
72
+ bounds: [[0, 0], [1, 1]],
73
+ resolution: 100,
74
+ zoom: 10,
75
+ isAtMaxZoom: false,
76
+ isAtMinZoom: false
67
77
  }
68
78
  map.once.mock.calls.find(([e]) => e === 'idle')[1]()
69
79
  expect(eventBus.emit).toHaveBeenCalledWith(events.MAP_FIRST_IDLE, state)
@@ -67,8 +67,12 @@ describe('MapLibreProvider', () => {
67
67
  })
68
68
 
69
69
  const doInitMap = (p, extra = {}) => p.initMap({
70
- container: 'div', padding: {}, mapStyle: { url: 'style.json', mapColorScheme: 'dark' },
71
- center: [0, 0], zoom: 5, ...extra
70
+ container: 'div',
71
+ padding: {},
72
+ mapStyle: { url: 'style.json', mapColorScheme: 'dark' },
73
+ center: [0, 0],
74
+ zoom: 5,
75
+ ...extra
72
76
  })
73
77
 
74
78
  test('constructor spreads mapProviderConfig and sets capabilities', () => {
@@ -5,7 +5,7 @@
5
5
  * @param {number} zoom - The current map zoom level.
6
6
  * @returns {number} The interpolated size value.
7
7
  */
8
- export function calculateLinearTextSize(expression, zoom) {
8
+ export function calculateLinearTextSize (expression, zoom) {
9
9
  const { stops } = expression
10
10
 
11
11
  if (stops.length < 2) {
@@ -40,10 +40,10 @@ export function calculateLinearTextSize(expression, zoom) {
40
40
 
41
41
  // 3. Perform Simple Linear Interpolation (LERP)
42
42
  // t is the proportion of the distance between Z0 and Z1 that 'zoom' has traveled.
43
- const t = (zoom - Z0) / (Z1 - Z0)
44
-
43
+ const t = (zoom - Z0) / (Z1 - Z0)
44
+
45
45
  // S0 + (S1 - S0) * t
46
46
  const interpolatedSize = S0 + (S1 - S0) * t
47
47
 
48
48
  return interpolatedSize
49
- }
49
+ }
@@ -23,9 +23,9 @@ describe('calculateLinearTextSize', () => {
23
23
 
24
24
  it('works with multiple stops', () => {
25
25
  const expr = { stops: [[0, 5], [5, 15], [10, 25]] }
26
- expect(calculateLinearTextSize(expr, -1)).toBe(5) // below first
27
- expect(calculateLinearTextSize(expr, 12)).toBe(25) // above last
26
+ expect(calculateLinearTextSize(expr, -1)).toBe(5) // below first
27
+ expect(calculateLinearTextSize(expr, 12)).toBe(25) // above last
28
28
  expect(calculateLinearTextSize(expr, 2.5)).toBe(10) // between first two
29
29
  expect(calculateLinearTextSize(expr, 7.5)).toBe(20) // between last two
30
30
  })
31
- })
31
+ })
@@ -60,4 +60,4 @@ describe('getWebGL', () => {
60
60
  error: 'WebGL is supported, but disabled'
61
61
  })
62
62
  })
63
- })
63
+ })
@@ -68,7 +68,7 @@ const calculateBounds = (LngLatBounds, renderedFeatures) => {
68
68
  }
69
69
 
70
70
  const bounds = new LngLatBounds()
71
-
71
+
72
72
  renderedFeatures.forEach(f => {
73
73
  const add = (c) => typeof c[0] === 'number' ? bounds.extend(c) : c.forEach(add)
74
74
  add(f.geometry.coordinates)
@@ -81,7 +81,7 @@ const calculateBounds = (LngLatBounds, renderedFeatures) => {
81
81
  * Update highlighted features using pure filters.
82
82
  * Supports fill + line geometry, multi-source, cleanup, and bounds.
83
83
  */
84
- export function updateHighlightedFeatures({ LngLatBounds, map, selectedFeatures, stylesMap }) {
84
+ export function updateHighlightedFeatures ({ LngLatBounds, map, selectedFeatures, stylesMap }) {
85
85
  if (!map) {
86
86
  return null
87
87
  }
@@ -2,7 +2,7 @@ import { updateHighlightedFeatures } from './highlightFeatures.js'
2
2
 
3
3
  describe('Highlighting Utils', () => {
4
4
  let map
5
- const LngLatBounds = function() {
5
+ const LngLatBounds = function () {
6
6
  this.coords = []
7
7
  this.extend = (c) => this.coords.push(c)
8
8
  this.getWest = () => Math.min(...this.coords.map(c => c[0]))
@@ -60,7 +60,7 @@ describe('Highlighting Utils', () => {
60
60
  // Line 13 verify: map.getLayer returned null and function returned early
61
61
  // Line 49-50 verify: Stale sources filtered out
62
62
  expect(map.setFilter).toHaveBeenCalledWith('highlight-stale-fill', ['==', 'id', ''])
63
-
63
+
64
64
  // Line 124 verify: Clear fill highlight when switching to line geometry
65
65
  expect(map.setFilter).toHaveBeenCalledWith('highlight-s2-fill', ['==', 'id', ''])
66
66
 
@@ -76,7 +76,9 @@ describe('Highlighting Utils', () => {
76
76
  map._highlightedSources = undefined
77
77
  map.getLayer.mockImplementation(id => id === 'l1' ? { source: 's1', type: 'line' } : null)
78
78
  map.queryRenderedFeatures.mockReturnValue([])
79
- updateHighlightedFeatures({ LngLatBounds, map,
79
+ updateHighlightedFeatures({
80
+ LngLatBounds,
81
+ map,
80
82
  selectedFeatures: [{ featureId: 1, layerId: 'l1' }],
81
83
  stylesMap: { l1: { stroke: 'red' } }
82
84
  })
@@ -88,7 +90,9 @@ describe('Highlighting Utils', () => {
88
90
  map._highlightedSources = new Set(['stale', 's1'])
89
91
  map.getLayer.mockImplementation(id => id === 'l1' ? { source: 's1', type: 'line' } : null)
90
92
  map.queryRenderedFeatures.mockReturnValue([])
91
- updateHighlightedFeatures({ LngLatBounds, map,
93
+ updateHighlightedFeatures({
94
+ LngLatBounds,
95
+ map,
92
96
  selectedFeatures: [{ featureId: 1, layerId: 'l1' }],
93
97
  stylesMap: { l1: { stroke: 'red' } }
94
98
  })
@@ -105,7 +109,9 @@ describe('Highlighting Utils', () => {
105
109
  return null
106
110
  })
107
111
  map.queryRenderedFeatures.mockReturnValue([])
108
- updateHighlightedFeatures({ LngLatBounds, map,
112
+ updateHighlightedFeatures({
113
+ LngLatBounds,
114
+ map,
109
115
  selectedFeatures: [
110
116
  { featureId: 1, layerId: 'l1' },
111
117
  { featureId: 2, layerId: 'l2' }
@@ -123,4 +129,4 @@ describe('Highlighting Utils', () => {
123
129
  const res = updateHighlightedFeatures({ LngLatBounds, map, selectedFeatures: [], stylesMap: {} })
124
130
  expect(res).toBeNull()
125
131
  })
126
- })
132
+ })
@@ -4,7 +4,7 @@ import { calculateLinearTextSize } from './calculateLinearTextSize.js'
4
4
  const HIGHLIGHT_SCALE_FACTOR = 1.5
5
5
  const HIGHLIGHT_LABEL_SOURCE = 'highlighted-label'
6
6
 
7
- export function getGeometryCenter(geometry) {
7
+ export function getGeometryCenter (geometry) {
8
8
  const { type, coordinates } = geometry
9
9
  if (type === 'Point') {
10
10
  return coordinates
@@ -24,7 +24,7 @@ export function getGeometryCenter(geometry) {
24
24
  return null
25
25
  }
26
26
 
27
- export function evalInterpolate(expr, zoom) {
27
+ export function evalInterpolate (expr, zoom) {
28
28
  if (typeof expr === 'number') {
29
29
  return expr
30
30
  }
@@ -50,14 +50,14 @@ export function evalInterpolate(expr, zoom) {
50
50
  return stops[stops.length - 1]
51
51
  }
52
52
 
53
- export function getHighlightColors(isDarkStyle) {
53
+ export function getHighlightColors (isDarkStyle) {
54
54
  if (isDarkStyle) {
55
55
  return { text: '#ffffff', halo: '#000000' }
56
56
  }
57
57
  return { text: '#000000', halo: '#ffffff' }
58
58
  }
59
59
 
60
- export function extractTextPropertyName(textField) {
60
+ export function extractTextPropertyName (textField) {
61
61
  if (typeof textField === 'string') {
62
62
  return /^{(.+)}$/.exec(textField)?.[1]
63
63
  }
@@ -67,7 +67,7 @@ export function extractTextPropertyName(textField) {
67
67
  return null
68
68
  }
69
69
 
70
- export function buildLabelFromFeature(feature, layer, propName, map) {
70
+ export function buildLabelFromFeature (feature, layer, propName, map) {
71
71
  const center = getGeometryCenter(feature.geometry)
72
72
  if (!center) {
73
73
  return null
@@ -76,7 +76,7 @@ export function buildLabelFromFeature(feature, layer, propName, map) {
76
76
  return { text: feature.properties[propName], x: projected.x, y: projected.y, feature, layer }
77
77
  }
78
78
 
79
- export function buildLabelsFromLayers(map, symbolLayers, features) {
79
+ export function buildLabelsFromLayers (map, symbolLayers, features) {
80
80
  return symbolLayers.flatMap(layer => {
81
81
  const textField = layer.layout?.['text-field']
82
82
  const propName = extractTextPropertyName(textField)
@@ -90,7 +90,7 @@ export function buildLabelsFromLayers(map, symbolLayers, features) {
90
90
  })
91
91
  }
92
92
 
93
- export function findClosestLabel(labels, centerPoint) {
93
+ export function findClosestLabel (labels, centerPoint) {
94
94
  return labels.reduce((best, label) => {
95
95
  const dist = (label.x - centerPoint.x) ** 2 + (label.y - centerPoint.y) ** 2
96
96
  if (!best || dist < best.dist) {
@@ -100,7 +100,7 @@ export function findClosestLabel(labels, centerPoint) {
100
100
  }, null)?.label
101
101
  }
102
102
 
103
- export function createHighlightLayerConfig(sourceLayer, highlightSize, colors) {
103
+ export function createHighlightLayerConfig (sourceLayer, highlightSize, colors) {
104
104
  return {
105
105
  id: `highlight-${sourceLayer.id}`,
106
106
  type: sourceLayer.type,
@@ -123,18 +123,17 @@ export function createHighlightLayerConfig(sourceLayer, highlightSize, colors) {
123
123
  }
124
124
  }
125
125
 
126
- export function removeHighlightLayer(map, state) {
126
+ export function removeHighlightLayer (map, state) {
127
127
  if (state.highlightLayerId && map.getLayer(state.highlightLayerId)) {
128
128
  try {
129
129
  map.removeLayer(state.highlightLayerId)
130
- }
131
- catch {}
130
+ } catch {}
132
131
  state.highlightLayerId = null
133
132
  state.highlightedExpr = null
134
133
  }
135
134
  }
136
135
 
137
- export function applyHighlight(map, labelData, state) {
136
+ export function applyHighlight (map, labelData, state) {
138
137
  if (!labelData?.feature?.layer) {
139
138
  return
140
139
  }
@@ -156,7 +155,7 @@ export function applyHighlight(map, labelData, state) {
156
155
  map.moveLayer(state.highlightLayerId)
157
156
  }
158
157
 
159
- export function navigateToNextLabel(direction, state) {
158
+ export function navigateToNextLabel (direction, state) {
160
159
  if (!state.currentPixel) {
161
160
  return null
162
161
  }
@@ -174,19 +173,19 @@ export function navigateToNextLabel(direction, state) {
174
173
  return state.labels[filtered[nextFilteredIndex].index]
175
174
  }
176
175
 
177
- function initLabelSource(map) {
176
+ function initLabelSource (map) {
178
177
  if (!map.getSource(HIGHLIGHT_LABEL_SOURCE)) {
179
178
  map.addSource(HIGHLIGHT_LABEL_SOURCE, { type: 'geojson', data: { type: 'FeatureCollection', features: [] } })
180
179
  }
181
180
  }
182
181
 
183
- function setLineCenterPlacement(map) {
182
+ function setLineCenterPlacement (map) {
184
183
  map.getStyle().layers
185
184
  .filter(l => l.layout?.['symbol-placement'] === 'line')
186
185
  .forEach(l => map.setLayoutProperty(l.id, 'symbol-placement', 'line-center'))
187
186
  }
188
187
 
189
- function setSymbolTextOpacity(map) {
188
+ function setSymbolTextOpacity (map) {
190
189
  map.getStyle().layers
191
190
  .filter(l => l.type === 'symbol')
192
191
  .forEach(layer => {
@@ -194,7 +193,7 @@ function setSymbolTextOpacity(map) {
194
193
  })
195
194
  }
196
195
 
197
- export function createMapLabelNavigator(map, mapColorScheme, events, eventBus) {
196
+ export function createMapLabelNavigator (map, mapColorScheme, events, eventBus) {
198
197
  const state = {
199
198
  isDarkStyle: mapColorScheme === 'dark',
200
199
  labels: [],
@@ -221,13 +220,13 @@ export function createMapLabelNavigator(map, mapColorScheme, events, eventBus) {
221
220
  }
222
221
  })
223
222
 
224
- function refreshLabels() {
223
+ function refreshLabels () {
225
224
  const symbolLayers = map.getStyle().layers.filter(l => l.type === 'symbol')
226
225
  const features = map.queryRenderedFeatures({ layers: symbolLayers.map(l => l.id) })
227
226
  state.labels = buildLabelsFromLayers(map, symbolLayers, features)
228
227
  }
229
228
 
230
- function highlightCenter() {
229
+ function highlightCenter () {
231
230
  refreshLabels()
232
231
  if (!state.labels.length) {
233
232
  return null
@@ -239,7 +238,7 @@ export function createMapLabelNavigator(map, mapColorScheme, events, eventBus) {
239
238
  return `${closest.text} (${closest.layer.id})`
240
239
  }
241
240
 
242
- function highlightNext(direction) {
241
+ function highlightNext (direction) {
243
242
  refreshLabels()
244
243
  if (!state.labels.length) {
245
244
  return null
@@ -5,14 +5,13 @@ import {
5
5
  navigateToNextLabel, createMapLabelNavigator
6
6
  } from './labels.js'
7
7
 
8
- jest.mock('./spatial.js', () => ({ spatialNavigate: jest.fn() }))
9
- jest.mock('./calculateLinearTextSize.js', () => ({ calculateLinearTextSize: jest.fn(() => 12) }))
10
-
11
8
  import { spatialNavigate } from './spatial.js'
12
9
  import { calculateLinearTextSize } from './calculateLinearTextSize.js'
13
10
 
14
- describe('labels utils', () => {
11
+ jest.mock('./spatial.js', () => ({ spatialNavigate: jest.fn() }))
12
+ jest.mock('./calculateLinearTextSize.js', () => ({ calculateLinearTextSize: jest.fn(() => 12) }))
15
13
 
14
+ describe('labels utils', () => {
16
15
  test('getGeometryCenter all geometry types', () => {
17
16
  expect(getGeometryCenter({ type: 'Point', coordinates: [1, 2] })).toEqual([1, 2])
18
17
  expect(getGeometryCenter({ type: 'MultiPoint', coordinates: [[3, 4]] })).toEqual([3, 4])
@@ -30,9 +29,9 @@ describe('labels utils', () => {
30
29
  expect(evalInterpolate(['literal', 'x'], 10)).toBe(12)
31
30
  expect(() => evalInterpolate(['interpolate', ['linear'], ['get', 'p'], 5, 10], 10)).toThrow()
32
31
  const expr = ['interpolate', ['linear'], ['zoom'], 5, 10, 10, 20]
33
- expect(evalInterpolate(expr, 3)).toBe(10) // zoom <= z0
34
- expect(evalInterpolate(expr, 7.5)).toBe(15) // interpolated
35
- expect(evalInterpolate(expr, 15)).toBe(20) // beyond last stop
32
+ expect(evalInterpolate(expr, 3)).toBe(10) // zoom <= z0
33
+ expect(evalInterpolate(expr, 7.5)).toBe(15) // interpolated
34
+ expect(evalInterpolate(expr, 15)).toBe(20) // beyond last stop
36
35
  })
37
36
 
38
37
  test('getHighlightColors', () => {
@@ -77,7 +76,7 @@ describe('labels utils', () => {
77
76
 
78
77
  test('findClosestLabel: empty → undefined; returns closest; skips farther', () => {
79
78
  expect(findClosestLabel([], { x: 0, y: 0 })).toBeUndefined()
80
- const labels = [{ x: 2, y: 0 }, { x: 10, y: 0 }] // closer first → second hits false branch
79
+ const labels = [{ x: 2, y: 0 }, { x: 10, y: 0 }] // closer first → second hits false branch
81
80
  expect(findClosestLabel(labels, { x: 0, y: 0 })).toBe(labels[0])
82
81
  })
83
82
 
@@ -109,9 +108,12 @@ describe('labels utils', () => {
109
108
 
110
109
  test('applyHighlight: early returns without feature.layer; applies otherwise', () => {
111
110
  const map = {
112
- getLayer: jest.fn(), removeLayer: jest.fn(),
111
+ getLayer: jest.fn(),
112
+ removeLayer: jest.fn(),
113
113
  getSource: jest.fn(() => ({ setData: jest.fn() })),
114
- getZoom: jest.fn(() => 10), addLayer: jest.fn(), moveLayer: jest.fn()
114
+ getZoom: jest.fn(() => 10),
115
+ addLayer: jest.fn(),
116
+ moveLayer: jest.fn()
115
117
  }
116
118
  const state = { highlightLayerId: null, highlightedExpr: null, isDarkStyle: false }
117
119
  applyHighlight(map, null, state)
@@ -132,9 +134,9 @@ describe('labels utils', () => {
132
134
  currentPixel: { x: 1, y: 1 }, labels: [{ x: 1, y: 1 }]
133
135
  })).toBeNull()
134
136
  const state = { currentPixel: { x: 0, y: 0 }, labels: [{ x: 0, y: 0 }, { x: 5, y: 5 }] }
135
- spatialNavigate.mockReturnValue(-1) // out of range → use 0
137
+ spatialNavigate.mockReturnValue(-1) // out of range → use 0
136
138
  expect(navigateToNextLabel('ArrowRight', state)).toBe(state.labels[1])
137
- spatialNavigate.mockReturnValue(0) // valid index
139
+ spatialNavigate.mockReturnValue(0) // valid index
138
140
  expect(navigateToNextLabel('ArrowRight', state)).toBe(state.labels[1])
139
141
  })
140
142
 
@@ -212,7 +214,7 @@ describe('labels utils', () => {
212
214
  })
213
215
 
214
216
  test('initLabelSource skips addSource when source exists; MAP_SET_STYLE triggers re-init', () => {
215
- map.getSource.mockReset().mockReturnValue({ setData: jest.fn() }) // source always exists
217
+ map.getSource.mockReset().mockReturnValue({ setData: jest.fn() }) // source always exists
216
218
  const eventBus = { on: jest.fn() }
217
219
  createMapLabelNavigator(map, 'light', { MAP_SET_STYLE: 'set-style' }, eventBus)
218
220
  expect(map.addSource).not.toHaveBeenCalled()