react-spatial 2.0.0-beta.0 → 2.0.0-beta.2

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 (124) hide show
  1. package/README.md +5 -10
  2. package/components/BaseLayerSwitcher/BaseLayerSwitcher.js +188 -107
  3. package/components/BaseLayerSwitcher/BaseLayerSwitcher.js.map +2 -2
  4. package/components/BaseLayerSwitcher/BaseLayerSwitcher.scss +6 -5
  5. package/components/BaseLayerSwitcher/index.js.map +2 -2
  6. package/components/BasicMap/BasicMap.js +116 -98
  7. package/components/BasicMap/BasicMap.js.map +2 -2
  8. package/components/BasicMap/index.js.map +2 -2
  9. package/components/CanvasSaveButton/CanvasSaveButton.js +448 -316
  10. package/components/CanvasSaveButton/CanvasSaveButton.js.map +2 -2
  11. package/components/CanvasSaveButton/CanvasSaveButton.md.scss +1 -1
  12. package/components/CanvasSaveButton/index.js.map +2 -2
  13. package/components/Copyright/Copyright.js +43 -35
  14. package/components/Copyright/Copyright.js.map +2 -2
  15. package/components/Copyright/index.js.map +2 -2
  16. package/components/FeatureExportButton/FeatureExportButton.js +35 -17
  17. package/components/FeatureExportButton/FeatureExportButton.js.map +2 -2
  18. package/components/FeatureExportButton/index.js.map +2 -2
  19. package/components/FitExtent/FitExtent.js +36 -18
  20. package/components/FitExtent/FitExtent.js.map +2 -2
  21. package/components/FitExtent/index.js.map +2 -2
  22. package/components/Geolocation/Geolocation.js +131 -92
  23. package/components/Geolocation/Geolocation.js.map +2 -2
  24. package/components/Geolocation/Geolocation.scss +7 -5
  25. package/components/Geolocation/index.js.map +2 -2
  26. package/components/LayerTree/LayerTree.js +361 -169
  27. package/components/LayerTree/LayerTree.js.map +2 -2
  28. package/components/LayerTree/LayerTree.scss +4 -6
  29. package/components/LayerTree/index.js.map +2 -2
  30. package/components/MousePosition/MousePosition.js +64 -33
  31. package/components/MousePosition/MousePosition.js.map +2 -2
  32. package/components/MousePosition/index.js.map +2 -2
  33. package/components/NorthArrow/NorthArrow.js +35 -19
  34. package/components/NorthArrow/NorthArrow.js.map +2 -2
  35. package/components/NorthArrow/index.js.map +2 -2
  36. package/components/Overlay/Overlay.js +100 -83
  37. package/components/Overlay/Overlay.js.map +2 -2
  38. package/components/Overlay/index.js.map +2 -2
  39. package/components/Permalink/Permalink.js +135 -90
  40. package/components/Permalink/Permalink.js.map +2 -2
  41. package/components/Permalink/index.js.map +2 -2
  42. package/components/Popup/Popup.js +134 -83
  43. package/components/Popup/Popup.js.map +2 -2
  44. package/components/Popup/Popup.md.scss +1 -0
  45. package/components/Popup/Popup.scss +3 -1
  46. package/components/Popup/index.js.map +2 -2
  47. package/components/ResizeHandler/ResizeHandler.js +51 -45
  48. package/components/ResizeHandler/ResizeHandler.js.map +2 -2
  49. package/components/ResizeHandler/index.js.map +2 -2
  50. package/components/RouteSchedule/RouteSchedule.js +218 -136
  51. package/components/RouteSchedule/RouteSchedule.js.map +2 -2
  52. package/components/RouteSchedule/RouteSchedule.md.scss +4 -2
  53. package/components/RouteSchedule/RouteSchedule.scss +12 -23
  54. package/components/RouteSchedule/index.js.map +2 -2
  55. package/components/ScaleLine/ScaleLine.js +11 -9
  56. package/components/ScaleLine/ScaleLine.js.map +2 -2
  57. package/components/ScaleLine/ScaleLine.scss +6 -4
  58. package/components/ScaleLine/index.js.map +2 -2
  59. package/components/StopsFinder/StopsFinder.js +141 -118
  60. package/components/StopsFinder/StopsFinder.js.map +2 -2
  61. package/components/StopsFinder/StopsFinderOption.js +11 -24
  62. package/components/StopsFinder/StopsFinderOption.js.map +2 -2
  63. package/components/StopsFinder/index.js.map +2 -2
  64. package/components/Zoom/Zoom.js +101 -62
  65. package/components/Zoom/Zoom.js.map +2 -2
  66. package/components/Zoom/Zoom.md.scss +3 -1
  67. package/components/Zoom/Zoom.scss +7 -5
  68. package/components/Zoom/index.js.map +2 -2
  69. package/images/geops_qr.png +0 -0
  70. package/package.json +81 -177
  71. package/propTypes.js +67 -0
  72. package/propTypes.js.map +7 -0
  73. package/setupTests.js +22 -0
  74. package/setupTests.js.map +7 -0
  75. package/themes/README.md +26 -0
  76. package/themes/default/components.scss +9 -13
  77. package/themes/default/examples.scss +20 -19
  78. package/themes/default/index.scss +3 -3
  79. package/themes/default/mixins.scss +7 -5
  80. package/themes/default/variables.scss +27 -25
  81. package/utils/GlobalsForOle.js +57 -57
  82. package/utils/GlobalsForOle.js.map +2 -2
  83. package/utils/KML.js +174 -49
  84. package/utils/KML.js.map +2 -2
  85. package/utils/Styles.js +7 -7
  86. package/utils/Styles.js.map +2 -2
  87. package/utils/getLayersAsFlatArray.js +14 -0
  88. package/utils/getLayersAsFlatArray.js.map +7 -0
  89. package/utils/getPolygonPattern.js.map +2 -2
  90. package/utils/timeUtils.js +11 -7
  91. package/utils/timeUtils.js.map +2 -2
  92. package/components/FilterButton/FilterButton.js +0 -66
  93. package/components/FilterButton/FilterButton.js.map +0 -7
  94. package/components/FilterButton/FilterButton.scss +0 -36
  95. package/components/FilterButton/index.js +0 -1
  96. package/components/FilterButton/index.js.map +0 -7
  97. package/components/FollowButton/FollowButton.js +0 -73
  98. package/components/FollowButton/FollowButton.js.map +0 -7
  99. package/components/FollowButton/FollowButton.scss +0 -36
  100. package/components/FollowButton/index.js +0 -1
  101. package/components/FollowButton/index.js.map +0 -7
  102. package/components/Search/Search.js +0 -166
  103. package/components/Search/Search.js.map +0 -7
  104. package/components/Search/Search.md.scss +0 -4
  105. package/components/Search/Search.scss +0 -78
  106. package/components/Search/SearchService.js +0 -48
  107. package/components/Search/SearchService.js.map +0 -7
  108. package/components/Search/engines/Engine.js +0 -19
  109. package/components/Search/engines/Engine.js.map +0 -7
  110. package/components/Search/engines/StopFinder.js +0 -30
  111. package/components/Search/engines/StopFinder.js.map +0 -7
  112. package/components/Search/index.js +0 -3
  113. package/components/Search/index.js.map +0 -7
  114. package/components/TrackerControl/TrackerControl.js +0 -116
  115. package/components/TrackerControl/TrackerControl.js.map +0 -7
  116. package/components/TrackerControl/TrackerControl.scss +0 -30
  117. package/components/TrackerControl/index.js +0 -1
  118. package/components/TrackerControl/index.js.map +0 -7
  119. package/images/FilterButton/filter.svg +0 -1
  120. package/images/FollowButton/follow.svg +0 -1
  121. package/images/baselayer/osm.baselayer.hot.png +0 -0
  122. package/images/baselayer/osm.baselayer.png +0 -0
  123. package/utils/KMLFormat.js +0 -69
  124. package/utils/KMLFormat.js.map +0 -7
package/README.md CHANGED
@@ -2,22 +2,21 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/react-spatial.svg?style=flat-square)](https://www.npmjs.com/package/react-spatial)
4
4
  [![build](https://github.com/geops/react-spatial/workflows/main/badge.svg)](https://github.com/geops/react-spatial/actions?query=workflow%3Amain)
5
- [![Renovate](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com)
6
5
  [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
7
- [![Netlify Status](https://api.netlify.com/api/v1/badges/8f7b7082-8998-4e1f-9a34-4d8cd18e6003/deploy-status)](https://app.netlify.com/sites/react-spatial/deploys)
6
+ ![Vercel](https://vercelbadge.vercel.app/api/geops/react-spatial)
8
7
 
9
- This library provides React components to build web applications and to visualize real-time geographical information based on [OpenLayers](https://openlayers.org/) and [Mapbox GL](https://docs.mapbox.com/mapbox-gl-js/api/).
8
+ This library provides React components to build web applications and to visualize real-time geographical information based on [OpenLayers](https://openlayers.org/) and [MapLibre GL JS](https://maplibre.org/maplibre-gl-js/).
10
9
 
11
- This library uses the [mobility-toolbox-js](https://mobility-toolbox-js.geops.io/) library.
10
+ This library uses the [mobility-toolbox-js](https://mobility-toolbox-js.geops.io/) library for some components.
12
11
 
13
- Documentation and examples at https://react-spatial.geops.de.
12
+ Documentation and examples at https://react-spatial.geops.io.
14
13
 
15
14
  ## Getting Started
16
15
 
17
16
  Install the [react-spatial](https://www.npmjs.com/package/react-spatial) package:
18
17
 
19
18
  ```bash
20
- yarn add mobility-toolbox-js mapbox-gl ol react-spatial
19
+ yarn add maplibre-gl ol mobility-toolbox-js react-spatial
21
20
  ```
22
21
 
23
22
  Your build pipeline needs to support ES6 modules and SASS.
@@ -37,7 +36,3 @@ import 'react-spatial/themes/default/index.scss';
37
36
  ## Bugs
38
37
 
39
38
  Please use the [GitHub issue tracker](https://github.com/geops/react-spatial/issues) for all bugs and feature requests. Before creating a new issue, do a quick search to see if the problem has been reported already.
40
-
41
- ## Version 1.x.x
42
-
43
- The master branch is now open for the version 2 development. The version 1 is now available in 1.x.x branch.
@@ -1,37 +1,61 @@
1
- import React, { useState, useEffect } from "react";
1
+ import Layer from "ol/layer/Layer";
2
+ import { unByKey } from "ol/Observable";
2
3
  import PropTypes from "prop-types";
4
+ import React, { useEffect, useState } from "react";
3
5
  import { FaChevronLeft } from "react-icons/fa";
4
- import { Layer } from "mobility-toolbox-js/ol";
5
6
  const propTypes = {
6
- layers: PropTypes.arrayOf(PropTypes.instanceOf(Layer)).isRequired,
7
- layerImages: PropTypes.objectOf(PropTypes.string),
7
+ /**
8
+ * CSS class to apply on the container.
9
+ */
8
10
  className: PropTypes.string,
9
- altText: PropTypes.string,
11
+ /**
12
+ * Image (node) rendered in the switcher close button.
13
+ */
14
+ closeButtonImage: PropTypes.node,
15
+ /**
16
+ * Function that returns the alternative text if the layer's image is not found.
17
+ */
18
+ getAltText: PropTypes.func,
19
+ /**
20
+ * Function that returns the label to display att the bootm of the layer's image and as title attribute.
21
+ */
22
+ getLayerLabel: PropTypes.func,
23
+ /**
24
+ * Object containing relative paths to the base layer images. Object
25
+ * keys need to correspond to layer keys
26
+ */
27
+ layerImages: PropTypes.objectOf(PropTypes.string),
28
+ /**
29
+ * An array of [mobility-toolbox-js layers](https://mobility-toolbox-js.geops.io/api/identifiers%20html#ol-layers).
30
+ */
31
+ layers: PropTypes.arrayOf(PropTypes.instanceOf(Layer)).isRequired,
32
+ /**
33
+ * Callback function on close button click.
34
+ * @param {function} Callback function triggered when a switcher button is clicked. Takes the event as argument.
35
+ */
36
+ onCloseButtonClick: PropTypes.func,
37
+ /**
38
+ * Callback function on layer button click.
39
+ * @param {function} Callback function triggered when a switcher button is clicked. Takes the event and the layer as arguments.
40
+ */
41
+ onLayerButtonClick: PropTypes.func,
42
+ /**
43
+ * Callback function on main switcher button click.
44
+ * @param {function} Callback function triggered when a switcher button is clicked. Takes the event as argument.
45
+ */
46
+ onSwitcherButtonClick: PropTypes.func,
47
+ /**
48
+ * Button titles.
49
+ */
10
50
  titles: PropTypes.shape({
11
51
  button: PropTypes.string,
12
- openSwitcher: PropTypes.string,
13
- closeSwitcher: PropTypes.string
14
- }),
15
- closeButtonImage: PropTypes.node,
16
- t: PropTypes.func
17
- };
18
- const defaultProps = {
19
- className: "rs-base-layer-switcher",
20
- altText: "Source not found",
21
- titles: {
22
- button: "Base layers",
23
- openSwitcher: "Open Baselayer-Switcher",
24
- closeSwitcher: "Close Baselayer-Switcher"
25
- },
26
- closeButtonImage: /* @__PURE__ */ React.createElement(FaChevronLeft, null),
27
- layerImages: void 0,
28
- t: (s) => {
29
- return s;
30
- }
52
+ closeSwitcher: PropTypes.string,
53
+ openSwitcher: PropTypes.string
54
+ })
31
55
  };
32
56
  const getVisibleLayer = (layers) => {
33
57
  return layers.find((layer) => {
34
- return layer.visible;
58
+ return layer.getVisible ? layer.getVisible() : layer.visible;
35
59
  });
36
60
  };
37
61
  const getNextImage = (currentLayer, layers, layerImages) => {
@@ -46,19 +70,56 @@ const getNextImage = (currentLayer, layers, layerImages) => {
46
70
  const getImageStyle = (url) => {
47
71
  return url ? {
48
72
  backgroundImage: `url(${url})`,
49
- backgroundSize: "cover",
73
+ backgroundPosition: "center",
50
74
  backgroundRepeat: "no-repeat",
51
- backgroundPosition: "center"
75
+ backgroundSize: "cover"
52
76
  } : null;
53
77
  };
78
+ function CloseButton({ children, onClick, tabIndex, title }) {
79
+ return /* @__PURE__ */ React.createElement(
80
+ "div",
81
+ {
82
+ "aria-label": title,
83
+ className: "rs-base-layer-switcher-close-btn",
84
+ onClick,
85
+ onKeyPress: (e) => {
86
+ return e.which === 13 && onClick();
87
+ },
88
+ role: "button",
89
+ tabIndex,
90
+ title
91
+ },
92
+ children
93
+ );
94
+ }
95
+ CloseButton.propTypes = {
96
+ children: PropTypes.node.isRequired,
97
+ onClick: PropTypes.func.isRequired,
98
+ tabIndex: PropTypes.string.isRequired,
99
+ title: PropTypes.string.isRequired
100
+ };
101
+ const defaultTitles = {
102
+ button: "Base layers",
103
+ closeSwitcher: "Close Baselayer-Switcher",
104
+ openSwitcher: "Open Baselayer-Switcher"
105
+ };
106
+ const getDefaultLabel = (layer) => {
107
+ return layer?.get("name") || "";
108
+ };
109
+ const getDefaultAltText = () => {
110
+ return "Source not found";
111
+ };
54
112
  function BaseLayerSwitcher({
55
- layers,
113
+ className = "rs-base-layer-switcher",
114
+ closeButtonImage = /* @__PURE__ */ React.createElement(FaChevronLeft, null),
115
+ getAltText = getDefaultAltText,
116
+ getLayerLabel = getDefaultLabel,
56
117
  layerImages,
57
- className,
58
- altText,
59
- titles,
60
- closeButtonImage,
61
- t
118
+ layers,
119
+ onCloseButtonClick,
120
+ onLayerButtonClick,
121
+ onSwitcherButtonClick,
122
+ titles = defaultTitles
62
123
  }) {
63
124
  const [switcherOpen, setSwitcherOpen] = useState(false);
64
125
  const [isClosed, setIsClosed] = useState(true);
@@ -72,11 +133,15 @@ function BaseLayerSwitcher({
72
133
  });
73
134
  const openClass = switcherOpen ? " rs-open" : "";
74
135
  const hiddenStyle = switcherOpen && !isClosed ? "visible" : "hidden";
75
- const handleSwitcherClick = () => {
136
+ const handleSwitcherClick = (evt) => {
137
+ const nextLayer = layers.find((layer) => {
138
+ return !(layer.getVisible ? layer.getVisible() : layer.visible);
139
+ });
140
+ const onButtonClick = layers.length === 2 ? onLayerButtonClick : onSwitcherButtonClick;
141
+ if (onButtonClick) {
142
+ onButtonClick(evt, nextLayer);
143
+ }
76
144
  if (layers.length === 2) {
77
- const nextLayer = layers.find((layer) => {
78
- return !layer.visible;
79
- });
80
145
  if (currentLayer.setVisible) {
81
146
  currentLayer.setVisible(false);
82
147
  } else {
@@ -92,7 +157,10 @@ function BaseLayerSwitcher({
92
157
  }
93
158
  return setSwitcherOpen(true) && setIsClosed(false);
94
159
  };
95
- const onLayerSelect = (layer) => {
160
+ const onLayerSelect = (layer, evt) => {
161
+ if (onLayerButtonClick) {
162
+ onLayerButtonClick(evt, layer);
163
+ }
96
164
  if (!switcherOpen) {
97
165
  setSwitcherOpen(true);
98
166
  return;
@@ -135,84 +203,97 @@ function BaseLayerSwitcher({
135
203
  return clearTimeout(timeout);
136
204
  };
137
205
  }, [switcherOpen]);
206
+ useEffect(() => {
207
+ const olKeys = (layers || []).map((layer) => {
208
+ return layer.on("change:visible", (evt) => {
209
+ const vis = evt.target.getVisible ? evt.target.getVisible() : evt.target.visible;
210
+ if (vis && currentLayer !== evt.target) {
211
+ setCurrentLayer(evt.target);
212
+ }
213
+ });
214
+ });
215
+ return () => {
216
+ unByKey(olKeys);
217
+ };
218
+ }, [currentLayer, layers]);
138
219
  if (!layers || layers.length < 2 || !currentLayer) {
139
220
  return null;
140
221
  }
141
- const toggleBtn = /* @__PURE__ */ React.createElement("div", {
142
- className: "rs-base-layer-switcher-btn-wrapper"
143
- }, /* @__PURE__ */ React.createElement("div", {
144
- className: "rs-base-layer-switcher-close-btn",
145
- role: "button",
146
- onClick: () => {
147
- return setSwitcherOpen(false);
148
- },
149
- onKeyPress: (e) => {
150
- return e.which === 13 && setSwitcherOpen(false);
151
- },
152
- tabIndex: switcherOpen ? "0" : "-1",
153
- "aria-label": titles.closeSwitcher,
154
- title: titles.closeSwitcher
155
- }, closeButtonImage));
156
- return /* @__PURE__ */ React.createElement("div", {
157
- className: `${className}${openClass}`
158
- }, /* @__PURE__ */ React.createElement("div", {
159
- className: `rs-base-layer-switcher-button rs-opener${openClass}`,
160
- role: "button",
161
- title: titles.openSwitcher,
162
- "aria-label": titles.openSwitcher,
163
- onClick: handleSwitcherClick,
164
- onKeyPress: (e) => {
165
- if (e.which === 13) {
166
- handleSwitcherClick();
167
- }
222
+ const firstNonVisibleLayer = layers.find((layer) => {
223
+ return !(layer.getVisible ? layer.getVisible() : layer.visible);
224
+ });
225
+ return /* @__PURE__ */ React.createElement("div", { className: `${className}${openClass}` }, /* @__PURE__ */ React.createElement(
226
+ "div",
227
+ {
228
+ "aria-label": titles.openSwitcher,
229
+ className: `rs-base-layer-switcher-button rs-opener${openClass}`,
230
+ onClick: handleSwitcherClick,
231
+ onKeyPress: (e) => {
232
+ if (e.which === 13) {
233
+ handleSwitcherClick();
234
+ }
235
+ },
236
+ role: "button",
237
+ style: getImageStyle(nextImage),
238
+ tabIndex: "0",
239
+ title: titles.openSwitcher
168
240
  },
169
- style: getImageStyle(nextImage),
170
- tabIndex: "0"
171
- }, /* @__PURE__ */ React.createElement("div", {
172
- className: "rs-base-layer-switcher-title"
173
- }, layers.length !== 2 ? titles.button : layers.find((layer) => {
174
- return !layer.visible;
175
- }) && t(
176
- layers.find((layer) => {
177
- return !layer.visible;
178
- }).name
179
- )), nextImage ? null : /* @__PURE__ */ React.createElement("span", {
180
- className: "rs-alt-text"
181
- }, t(altText))), layers.map((layer, idx) => {
182
- const layerName = layer.name;
183
- const activeClass = layerName === currentLayer.name ? " rs-active" : "";
241
+ /* @__PURE__ */ React.createElement("div", { className: "rs-base-layer-switcher-title" }, layers.length !== 2 ? titles.button : firstNonVisibleLayer && getLayerLabel(firstNonVisibleLayer)),
242
+ nextImage ? null : /* @__PURE__ */ React.createElement("span", { className: "rs-alt-text" }, getAltText(firstNonVisibleLayer))
243
+ ), layers.map((layer, idx) => {
244
+ const layerName = getLayerLabel(layer);
245
+ const activeClass = layerName === currentLayer.get("name") ? " rs-active" : "";
184
246
  const imageStyle = getImageStyle(
185
- layerImages ? layerImages[`${layer.key}`] : layer.get("previewImage")
247
+ layerImages ? layerImages[`${layer.get("key") || layer.key}`] : layer.get("previewImage")
186
248
  );
187
- return /* @__PURE__ */ React.createElement("div", {
188
- key: layer.key,
189
- className: "rs-base-layer-switcher-btn-wrapper",
190
- style: {
191
- overflow: hiddenStyle,
192
- zIndex: layers.length - idx
193
- }
194
- }, /* @__PURE__ */ React.createElement("div", {
195
- className: `rs-base-layer-switcher-button${openClass}`,
196
- role: "button",
197
- title: t(layerName),
198
- "aria-label": t(layerName),
199
- onClick: () => {
200
- return onLayerSelect(layer);
249
+ return /* @__PURE__ */ React.createElement(
250
+ "div",
251
+ {
252
+ className: "rs-base-layer-switcher-btn-wrapper",
253
+ key: layer.key,
254
+ style: {
255
+ /* stylelint-disable-next-line value-keyword-case */
256
+ overflow: hiddenStyle,
257
+ /* stylelint-disable-next-line value-keyword-case */
258
+ zIndex: layers.length - idx
259
+ }
201
260
  },
202
- onKeyPress: (e) => {
203
- if (e.which === 13) {
204
- onLayerSelect(layer);
261
+ /* @__PURE__ */ React.createElement(
262
+ "div",
263
+ {
264
+ "aria-label": layerName,
265
+ className: `rs-base-layer-switcher-button${openClass}`,
266
+ onClick: (evt) => {
267
+ return onLayerSelect(layer, evt);
268
+ },
269
+ onKeyPress: (evt) => {
270
+ if (evt.which === 13) {
271
+ onLayerSelect(layer, evt);
272
+ }
273
+ },
274
+ role: "button",
275
+ style: imageStyle,
276
+ tabIndex: switcherOpen ? "0" : "-1",
277
+ title: layerName
278
+ },
279
+ /* @__PURE__ */ React.createElement("div", { className: `rs-base-layer-switcher-title${activeClass}` }, layerName),
280
+ imageStyle ? null : /* @__PURE__ */ React.createElement("span", { className: "rs-alt-text" }, getAltText(layer))
281
+ )
282
+ );
283
+ }), /* @__PURE__ */ React.createElement(
284
+ CloseButton,
285
+ {
286
+ onClick: (evt) => {
287
+ if (onCloseButtonClick) {
288
+ onCloseButtonClick(evt);
205
289
  }
290
+ setSwitcherOpen(false);
206
291
  },
207
- style: imageStyle,
208
- tabIndex: switcherOpen ? "0" : "-1"
209
- }, /* @__PURE__ */ React.createElement("div", {
210
- className: `rs-base-layer-switcher-title${activeClass}`
211
- }, t(layerName)), imageStyle ? null : /* @__PURE__ */ React.createElement("span", {
212
- className: "rs-alt-text"
213
- }, t(altText))));
214
- }), toggleBtn);
292
+ tabIndex: switcherOpen ? "0" : "-1",
293
+ title: titles.closeSwitcher
294
+ },
295
+ closeButtonImage
296
+ ));
215
297
  }
216
298
  BaseLayerSwitcher.propTypes = propTypes;
217
- BaseLayerSwitcher.defaultProps = defaultProps;
218
299
  export default BaseLayerSwitcher;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/BaseLayerSwitcher/BaseLayerSwitcher.js"],
4
- "sourcesContent": ["/* eslint-disable jsx-a11y/interactive-supports-focus */\nimport React, { useState, useEffect } from 'react';\nimport PropTypes from 'prop-types';\nimport { FaChevronLeft } from 'react-icons/fa';\nimport { Layer } from 'mobility-toolbox-js/ol';\n\nconst propTypes = {\n /**\n * An array of [mobility-toolbox-js layers](https://mobility-toolbox-js.geops.io/api/identifiers%20html#ol-layers).\n */\n layers: PropTypes.arrayOf(PropTypes.instanceOf(Layer)).isRequired,\n\n /**\n * Object containing relative paths to the base layer images. Object\n * keys need to correspond to layer keys\n */\n layerImages: PropTypes.objectOf(PropTypes.string),\n\n /**\n * CSS class to apply on the container.\n */\n className: PropTypes.string,\n\n /**\n * Alternative text rendered if layer images can't be loaded\n */\n altText: PropTypes.string,\n\n /**\n * Button titles.\n */\n titles: PropTypes.shape({\n button: PropTypes.string,\n openSwitcher: PropTypes.string,\n closeSwitcher: PropTypes.string,\n }),\n\n /**\n * Image (node) rendered in the switcher close button.\n */\n closeButtonImage: PropTypes.node,\n\n /**\n * Translation function.\n * @param {function} Translation function returning the translated string.\n */\n t: PropTypes.func,\n};\n\nconst defaultProps = {\n className: 'rs-base-layer-switcher',\n altText: 'Source not found',\n titles: {\n button: 'Base layers',\n openSwitcher: 'Open Baselayer-Switcher',\n closeSwitcher: 'Close Baselayer-Switcher',\n },\n closeButtonImage: <FaChevronLeft />,\n layerImages: undefined,\n t: (s) => {\n return s;\n },\n};\n\nconst getVisibleLayer = (layers) => {\n return layers.find((layer) => {\n return layer.visible;\n });\n};\n\nconst getNextImage = (currentLayer, layers, layerImages) => {\n const currentIndex = layers.indexOf(\n layers.find((layer) => {\n return layer === currentLayer;\n }),\n );\n const nextIndex = currentIndex + 1 === layers.length ? 0 : currentIndex + 1;\n return layerImages[nextIndex];\n};\n\nconst getImageStyle = (url) => {\n return url\n ? {\n backgroundImage: `url(${url})`,\n backgroundSize: 'cover',\n backgroundRepeat: 'no-repeat',\n backgroundPosition: 'center',\n }\n : null;\n};\n\n/**\n * The BaseLayerSwitcher component renders a button interface for switching the visible\n * [mobility-toolbox-js layer](https://mobility-toolbox-js.geops.io/api/identifiers%20html#ol-layers)\n * when defined as base layer.\n */\n\nfunction BaseLayerSwitcher({\n layers,\n layerImages,\n className,\n altText,\n titles,\n closeButtonImage,\n t,\n}) {\n const [switcherOpen, setSwitcherOpen] = useState(false);\n const [isClosed, setIsClosed] = useState(true);\n const [currentLayer, setCurrentLayer] = useState(\n getVisibleLayer(layers) || layers[0],\n );\n\n /* Images are loaded from props if provided, fallback from layer */\n const images = layerImages\n ? Object.keys(layerImages).map((layerImage) => {\n return layerImages[layerImage];\n })\n : layers.map((layer) => {\n return layer.get('previewImage');\n });\n\n const openClass = switcherOpen ? ' rs-open' : '';\n const hiddenStyle = switcherOpen && !isClosed ? 'visible' : 'hidden';\n\n const handleSwitcherClick = () => {\n if (layers.length === 2) {\n /* On only two layer options the opener becomes a layer toggle button */\n const nextLayer = layers.find((layer) => {\n return !layer.visible;\n });\n if (currentLayer.setVisible) {\n currentLayer.setVisible(false);\n } else {\n currentLayer.visible = false;\n }\n setCurrentLayer(nextLayer);\n if (nextLayer.setVisible) {\n nextLayer.setVisible(true);\n } else {\n nextLayer.visible = true;\n }\n return;\n }\n // eslint-disable-next-line consistent-return\n return setSwitcherOpen(true) && setIsClosed(false);\n };\n\n const onLayerSelect = (layer) => {\n if (!switcherOpen) {\n setSwitcherOpen(true);\n return;\n }\n setCurrentLayer(layer);\n if (layer.setVisible) {\n layer.setVisible(true);\n } else {\n // eslint-disable-next-line no-param-reassign\n layer.visible = true;\n }\n layers\n .filter((l) => {\n return l !== layer;\n })\n .forEach((l) => {\n if (l.setVisible) {\n l.setVisible(false);\n } else {\n // eslint-disable-next-line no-param-reassign\n l.visible = false;\n }\n });\n setSwitcherOpen(false);\n };\n\n /* Get next image for closed button */\n const nextImage = getNextImage(currentLayer, layers, images);\n\n useEffect(() => {\n /* Ensure correct layer is active on app load */\n if (currentLayer !== getVisibleLayer(layers)) {\n setCurrentLayer(getVisibleLayer(layers) || layers[0]);\n }\n }, [currentLayer, layers]);\n\n useEffect(() => {\n /* Used for correct layer image render with animation */\n let timeout;\n if (!switcherOpen) {\n timeout = setTimeout(() => {\n setIsClosed(true);\n }, 200);\n } else {\n timeout = setTimeout(() => {\n setIsClosed(false);\n }, 800);\n }\n return () => {\n return clearTimeout(timeout);\n };\n }, [switcherOpen]);\n\n if (!layers || layers.length < 2 || !currentLayer) {\n return null;\n }\n\n const toggleBtn = (\n <div className=\"rs-base-layer-switcher-btn-wrapper\">\n <div\n className=\"rs-base-layer-switcher-close-btn\"\n role=\"button\"\n onClick={() => {\n return setSwitcherOpen(false);\n }}\n onKeyPress={(e) => {\n return e.which === 13 && setSwitcherOpen(false);\n }}\n tabIndex={switcherOpen ? '0' : '-1'}\n aria-label={titles.closeSwitcher}\n title={titles.closeSwitcher}\n >\n {closeButtonImage}\n </div>\n </div>\n );\n\n return (\n <div className={`${className}${openClass}`}>\n <div\n className={`rs-base-layer-switcher-button rs-opener${openClass}`}\n role=\"button\"\n title={titles.openSwitcher}\n aria-label={titles.openSwitcher}\n onClick={handleSwitcherClick}\n onKeyPress={(e) => {\n if (e.which === 13) {\n handleSwitcherClick();\n }\n }}\n style={getImageStyle(nextImage)}\n tabIndex=\"0\"\n >\n <div className=\"rs-base-layer-switcher-title\">\n {layers.length !== 2\n ? titles.button\n : layers.find((layer) => {\n return !layer.visible;\n }) &&\n t(\n layers.find((layer) => {\n return !layer.visible;\n }).name,\n )}\n </div>\n {nextImage ? null : <span className=\"rs-alt-text\">{t(altText)}</span>}\n </div>\n {layers.map((layer, idx) => {\n const layerName = layer.name;\n const activeClass = layerName === currentLayer.name ? ' rs-active' : '';\n const imageStyle = getImageStyle(\n layerImages ? layerImages[`${layer.key}`] : layer.get('previewImage'),\n );\n return (\n <div\n key={layer.key}\n className=\"rs-base-layer-switcher-btn-wrapper\"\n style={{\n /* stylelint-disable-next-line value-keyword-case */\n overflow: hiddenStyle,\n /* stylelint-disable-next-line value-keyword-case */\n zIndex: layers.length - idx,\n }}\n >\n <div\n className={`rs-base-layer-switcher-button${openClass}`}\n role=\"button\"\n title={t(layerName)}\n aria-label={t(layerName)}\n onClick={() => {\n return onLayerSelect(layer);\n }}\n onKeyPress={(e) => {\n if (e.which === 13) {\n onLayerSelect(layer);\n }\n }}\n style={imageStyle}\n tabIndex={switcherOpen ? '0' : '-1'}\n >\n <div className={`rs-base-layer-switcher-title${activeClass}`}>\n {t(layerName)}\n </div>\n {imageStyle ? null : (\n <span className=\"rs-alt-text\">{t(altText)}</span>\n )}\n </div>\n </div>\n );\n })}\n {toggleBtn}\n </div>\n );\n}\n\nBaseLayerSwitcher.propTypes = propTypes;\nBaseLayerSwitcher.defaultProps = defaultProps;\n\nexport default BaseLayerSwitcher;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import Layer from \"ol/layer/Layer\";\nimport { unByKey } from \"ol/Observable\";\nimport PropTypes from \"prop-types\";\n/* eslint-disable jsx-a11y/interactive-supports-focus */\nimport React, { useEffect, useState } from \"react\";\nimport { FaChevronLeft } from \"react-icons/fa\";\n\nconst propTypes = {\n /**\n * CSS class to apply on the container.\n */\n className: PropTypes.string,\n\n /**\n * Image (node) rendered in the switcher close button.\n */\n closeButtonImage: PropTypes.node,\n\n /**\n * Function that returns the alternative text if the layer's image is not found.\n */\n getAltText: PropTypes.func,\n\n /**\n * Function that returns the label to display att the bootm of the layer's image and as title attribute.\n */\n getLayerLabel: PropTypes.func,\n\n /**\n * Object containing relative paths to the base layer images. Object\n * keys need to correspond to layer keys\n */\n layerImages: PropTypes.objectOf(PropTypes.string),\n\n /**\n * An array of [mobility-toolbox-js layers](https://mobility-toolbox-js.geops.io/api/identifiers%20html#ol-layers).\n */\n layers: PropTypes.arrayOf(PropTypes.instanceOf(Layer)).isRequired,\n\n /**\n * Callback function on close button click.\n * @param {function} Callback function triggered when a switcher button is clicked. Takes the event as argument.\n */\n onCloseButtonClick: PropTypes.func,\n\n /**\n * Callback function on layer button click.\n * @param {function} Callback function triggered when a switcher button is clicked. Takes the event and the layer as arguments.\n */\n onLayerButtonClick: PropTypes.func,\n\n /**\n * Callback function on main switcher button click.\n * @param {function} Callback function triggered when a switcher button is clicked. Takes the event as argument.\n */\n onSwitcherButtonClick: PropTypes.func,\n\n /**\n * Button titles.\n */\n titles: PropTypes.shape({\n button: PropTypes.string,\n closeSwitcher: PropTypes.string,\n openSwitcher: PropTypes.string,\n }),\n};\n\nconst getVisibleLayer = (layers) => {\n return layers.find((layer) => {\n return layer.getVisible ? layer.getVisible() : layer.visible;\n });\n};\n\nconst getNextImage = (currentLayer, layers, layerImages) => {\n const currentIndex = layers.indexOf(\n layers.find((layer) => {\n return layer === currentLayer;\n }),\n );\n const nextIndex = currentIndex + 1 === layers.length ? 0 : currentIndex + 1;\n return layerImages[nextIndex];\n};\n\nconst getImageStyle = (url) => {\n return url\n ? {\n backgroundImage: `url(${url})`,\n backgroundPosition: \"center\",\n backgroundRepeat: \"no-repeat\",\n backgroundSize: \"cover\",\n }\n : null;\n};\n\nfunction CloseButton({ children, onClick, tabIndex, title }) {\n return (\n <div\n aria-label={title}\n className=\"rs-base-layer-switcher-close-btn\"\n onClick={onClick}\n onKeyPress={(e) => {\n return e.which === 13 && onClick();\n }}\n role=\"button\"\n tabIndex={tabIndex}\n title={title}\n >\n {children}\n </div>\n );\n}\n\nCloseButton.propTypes = {\n children: PropTypes.node.isRequired,\n onClick: PropTypes.func.isRequired,\n tabIndex: PropTypes.string.isRequired,\n title: PropTypes.string.isRequired,\n};\n\nconst defaultTitles = {\n button: \"Base layers\",\n closeSwitcher: \"Close Baselayer-Switcher\",\n openSwitcher: \"Open Baselayer-Switcher\",\n};\n\nconst getDefaultLabel = (layer) => {\n return layer?.get(\"name\") || \"\";\n};\n\nconst getDefaultAltText = () => {\n return \"Source not found\";\n};\n\n/**\n * The BaseLayerSwitcher component renders a button interface for switching the visible\n * when defined as base layer.\n */\n\nfunction BaseLayerSwitcher({\n className = \"rs-base-layer-switcher\",\n closeButtonImage = <FaChevronLeft />,\n getAltText = getDefaultAltText,\n getLayerLabel = getDefaultLabel,\n layerImages,\n layers,\n onCloseButtonClick,\n onLayerButtonClick,\n onSwitcherButtonClick,\n titles = defaultTitles,\n}) {\n const [switcherOpen, setSwitcherOpen] = useState(false);\n const [isClosed, setIsClosed] = useState(true);\n const [currentLayer, setCurrentLayer] = useState(\n getVisibleLayer(layers) || layers[0],\n );\n\n /* Images are loaded from props if provided, fallback from layer */\n const images = layerImages\n ? Object.keys(layerImages).map((layerImage) => {\n return layerImages[layerImage];\n })\n : layers.map((layer) => {\n return layer.get(\"previewImage\");\n });\n\n const openClass = switcherOpen ? \" rs-open\" : \"\";\n const hiddenStyle = switcherOpen && !isClosed ? \"visible\" : \"hidden\";\n\n const handleSwitcherClick = (evt) => {\n const nextLayer = layers.find((layer) => {\n return !(layer.getVisible ? layer.getVisible() : layer.visible);\n });\n const onButtonClick =\n layers.length === 2 ? onLayerButtonClick : onSwitcherButtonClick;\n if (onButtonClick) {\n onButtonClick(evt, nextLayer);\n }\n if (layers.length === 2) {\n /* On only two layer options the opener becomes a layer toggle button */\n if (currentLayer.setVisible) {\n currentLayer.setVisible(false);\n } else {\n currentLayer.visible = false;\n }\n setCurrentLayer(nextLayer);\n if (nextLayer.setVisible) {\n nextLayer.setVisible(true);\n } else {\n nextLayer.visible = true;\n }\n return;\n }\n // eslint-disable-next-line consistent-return\n return setSwitcherOpen(true) && setIsClosed(false);\n };\n\n const onLayerSelect = (layer, evt) => {\n if (onLayerButtonClick) {\n onLayerButtonClick(evt, layer);\n }\n if (!switcherOpen) {\n setSwitcherOpen(true);\n return;\n }\n setCurrentLayer(layer);\n if (layer.setVisible) {\n layer.setVisible(true);\n } else {\n // eslint-disable-next-line no-param-reassign\n layer.visible = true;\n }\n layers\n .filter((l) => {\n return l !== layer;\n })\n .forEach((l) => {\n if (l.setVisible) {\n l.setVisible(false);\n } else {\n // eslint-disable-next-line no-param-reassign\n l.visible = false;\n }\n });\n setSwitcherOpen(false);\n };\n\n /* Get next image for closed button */\n const nextImage = getNextImage(currentLayer, layers, images);\n\n useEffect(() => {\n /* Ensure correct layer is active on app load */\n if (currentLayer !== getVisibleLayer(layers)) {\n setCurrentLayer(getVisibleLayer(layers) || layers[0]);\n }\n }, [currentLayer, layers]);\n\n useEffect(() => {\n /* Used for correct layer image render with animation */\n let timeout;\n if (!switcherOpen) {\n timeout = setTimeout(() => {\n setIsClosed(true);\n }, 200);\n } else {\n timeout = setTimeout(() => {\n setIsClosed(false);\n }, 800);\n }\n return () => {\n return clearTimeout(timeout);\n };\n }, [switcherOpen]);\n\n useEffect(() => {\n // Update the layer selected when a visibility changes.\n const olKeys = (layers || []).map((layer) => {\n return layer.on(\"change:visible\", (evt) => {\n const vis = evt.target.getVisible\n ? evt.target.getVisible()\n : evt.target.visible;\n if (vis && currentLayer !== evt.target) {\n setCurrentLayer(evt.target);\n }\n });\n });\n return () => {\n unByKey(olKeys);\n };\n }, [currentLayer, layers]);\n\n if (!layers || layers.length < 2 || !currentLayer) {\n return null;\n }\n\n const firstNonVisibleLayer = layers.find((layer) => {\n return !(layer.getVisible ? layer.getVisible() : layer.visible);\n });\n\n return (\n <div className={`${className}${openClass}`}>\n <div\n aria-label={titles.openSwitcher}\n className={`rs-base-layer-switcher-button rs-opener${openClass}`}\n onClick={handleSwitcherClick}\n onKeyPress={(e) => {\n if (e.which === 13) {\n handleSwitcherClick();\n }\n }}\n role=\"button\"\n style={getImageStyle(nextImage)}\n tabIndex=\"0\"\n title={titles.openSwitcher}\n >\n <div className=\"rs-base-layer-switcher-title\">\n {layers.length !== 2\n ? titles.button\n : firstNonVisibleLayer && getLayerLabel(firstNonVisibleLayer)}\n </div>\n {nextImage ? null : (\n <span className=\"rs-alt-text\">\n {getAltText(firstNonVisibleLayer)}\n </span>\n )}\n </div>\n {layers.map((layer, idx) => {\n const layerName = getLayerLabel(layer);\n const activeClass =\n layerName === currentLayer.get(\"name\") ? \" rs-active\" : \"\";\n const imageStyle = getImageStyle(\n layerImages\n ? layerImages[`${layer.get(\"key\") || layer.key}`]\n : layer.get(\"previewImage\"),\n );\n return (\n <div\n className=\"rs-base-layer-switcher-btn-wrapper\"\n key={layer.key}\n style={{\n /* stylelint-disable-next-line value-keyword-case */\n overflow: hiddenStyle,\n /* stylelint-disable-next-line value-keyword-case */\n zIndex: layers.length - idx,\n }}\n >\n <div\n aria-label={layerName}\n className={`rs-base-layer-switcher-button${openClass}`}\n onClick={(evt) => {\n return onLayerSelect(layer, evt);\n }}\n onKeyPress={(evt) => {\n if (evt.which === 13) {\n onLayerSelect(layer, evt);\n }\n }}\n role=\"button\"\n style={imageStyle}\n tabIndex={switcherOpen ? \"0\" : \"-1\"}\n title={layerName}\n >\n <div className={`rs-base-layer-switcher-title${activeClass}`}>\n {layerName}\n </div>\n {imageStyle ? null : (\n <span className=\"rs-alt-text\">{getAltText(layer)}</span>\n )}\n </div>\n </div>\n );\n })}\n <CloseButton\n onClick={(evt) => {\n if (onCloseButtonClick) {\n onCloseButtonClick(evt);\n }\n setSwitcherOpen(false);\n }}\n tabIndex={switcherOpen ? \"0\" : \"-1\"}\n title={titles.closeSwitcher}\n >\n {closeButtonImage}\n </CloseButton>\n </div>\n );\n}\n\nBaseLayerSwitcher.propTypes = propTypes;\n\nexport default BaseLayerSwitcher;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -4,7 +4,8 @@
4
4
  transition: 800ms width;
5
5
  overflow: hidden;
6
6
  display: flex;
7
- padding: 2px 2px;
7
+ align-items: center;
8
+ padding: 2px;
8
9
  pointer-events: none;
9
10
 
10
11
  &.rs-open {
@@ -20,15 +21,15 @@
20
21
  width: 100px;
21
22
  min-width: 100px;
22
23
  margin-right: 4px;
23
- background-color: rgb(197, 197, 197);
24
+ background-color: rgb(197 197 197);
24
25
  border: 2px solid white;
25
26
  box-sizing: border-box;
26
27
  pointer-events: auto;
27
28
 
28
29
  &.rs-opener {
29
30
  position: absolute;
30
- top: 2px; // For IE
31
- left: 2px; // For IE
31
+ top: 2px; /* For IE */
32
+ left: 2px; /* For IE */
32
33
  opacity: 1;
33
34
  z-index: 100;
34
35
  transition: 700ms opacity, 1000ms z-index;
@@ -81,7 +82,7 @@
81
82
  font-size: 10px;
82
83
  padding: 2px 0;
83
84
  color: white;
84
- background-color: rgba(0, 0, 0, 0.7);
85
+ background-color: rgb(0 0 0 / 70%);
85
86
  text-align: center;
86
87
 
87
88
  &.rs-active {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/BaseLayerSwitcher/index.js"],
4
- "sourcesContent": ["export { default } from './BaseLayerSwitcher';\n"],
5
- "mappings": "AAAA,wBAAwB;",
4
+ "sourcesContent": ["export { default } from \"./BaseLayerSwitcher\";\n"],
5
+ "mappings": "AAAA,SAAS,eAAe;",
6
6
  "names": []
7
7
  }