@geops/rvf-mobility-web-component 0.1.60 → 0.1.62

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 (73) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +1 -0
  3. package/docutils.js +103 -4
  4. package/fonts/source-sans-3/source-sans-3-v15-latin-500.ttf +0 -0
  5. package/fonts/source-sans-3/source-sans-3-v15-latin-500.woff2 +0 -0
  6. package/fonts/source-sans-3/source-sans-3-v15-latin-600.ttf +0 -0
  7. package/fonts/source-sans-3/source-sans-3-v15-latin-600.woff2 +0 -0
  8. package/fonts/source-sans-3/source-sans-3-v15-latin-700.ttf +0 -0
  9. package/fonts/source-sans-3/source-sans-3-v15-latin-700.woff2 +0 -0
  10. package/fonts/source-sans-3/source-sans-3-v15-latin-regular.ttf +0 -0
  11. package/fonts/source-sans-3/source-sans-3-v15-latin-regular.woff2 +0 -0
  12. package/index.html +28 -94
  13. package/index.js +235 -224
  14. package/notifications.html +144 -0
  15. package/package.json +2 -2
  16. package/search.html +24 -65
  17. package/src/FeatureDetails/FeatureDetails.tsx +20 -6
  18. package/src/FeaturesInfosListener/FeaturesInfosListener.tsx +2 -0
  19. package/src/LayerTree/TreeItem/TreeItem.tsx +2 -2
  20. package/src/LayerTreeMenu/LayerTreeMenu.tsx +19 -3
  21. package/src/LayoutState/LayoutState.tsx +17 -0
  22. package/src/LinesNetworkPlanDetails/LinesNetworkPlanDetails.tsx +34 -21
  23. package/src/LinesNetworkPlanLayer/LinesNetworkPlanLayer.tsx +3 -6
  24. package/src/LinesNetworkPlanLayerHighlight/LinesNetworkPlanLayerHighlight.tsx +88 -0
  25. package/src/LinesNetworkPlanLayerHighlight/index.tsx +1 -0
  26. package/src/MapDispatchEvents/MapDispatchEvents.tsx +6 -4
  27. package/src/MapLayout/MapLayout.tsx +2 -2
  28. package/src/MapsetLayer/MapsetLayer.tsx +116 -0
  29. package/src/MapsetLayer/index.tsx +1 -0
  30. package/src/MobilityMap/MobilityMap.tsx +27 -5
  31. package/src/MobilityMap/MobilityMapAttributes.test.ts +38 -0
  32. package/src/MobilityMap/MobilityMapAttributes.ts +99 -22
  33. package/src/MobilityMap/MobilityMapEvents.ts +53 -0
  34. package/src/MobilityNotifications/MobilityNotifications.tsx +93 -0
  35. package/src/MobilityNotifications/MobilityNotificationsAttributes.test.ts +21 -0
  36. package/src/MobilityNotifications/MobilityNotificationsAttributes.ts +46 -0
  37. package/src/MobilityNotifications/index.ts +2 -0
  38. package/src/MobilitySearch/MobilitySearchEvents.ts +21 -0
  39. package/src/NotificationDetails/NotificationDetails.tsx +74 -251
  40. package/src/OverlayContent/OverlayContent.tsx +1 -1
  41. package/src/OverlayDetails/OverlayDetails.tsx +4 -2
  42. package/src/OverlayFooter/OverlayFooter.tsx +3 -2
  43. package/src/RealtimeLayer/RealtimeLayer.tsx +36 -7
  44. package/src/RouteScheduleFooter/RouteScheduleFooter.tsx +1 -2
  45. package/src/RvfFeatureDetails/RvfFeatureDetails.tsx +2 -2
  46. package/src/RvfFeatureDetails/RvfLineNetworkDetails/RvfLineNetworkDetails.tsx +2 -0
  47. package/src/RvfFeatureDetails/RvfNotificationDetails/RvfNotificationDetails.tsx +12 -453
  48. package/src/RvfFeatureDetails/RvfSellingPointDetails/RvfSellingPointDetails.tsx +20 -17
  49. package/src/RvfFeatureDetails/RvfSharedMobilityDetail/RvfSharedMobilityDetails.tsx +93 -36
  50. package/src/RvfLink/RvfLink.tsx +5 -2
  51. package/src/RvfMobilityMap/RvfMobilityMap.tsx +28 -11
  52. package/src/RvfSelectedFeatureHighlightLayer/RvfSelectedFeatureHighlightLayer.tsx +9 -5
  53. package/src/RvfSingleClickListener/RvfSingleClickListener.tsx +3 -1
  54. package/src/SituationDetails/SituationDetails.tsx +324 -0
  55. package/src/SituationDetails/index.ts +1 -0
  56. package/src/index.tsx +16 -0
  57. package/src/indexDoc.ts +25 -3
  58. package/src/ui/Checkbox/Checkbox.tsx +2 -2
  59. package/src/ui/Link/Link.tsx +49 -0
  60. package/src/ui/Link/index.tsx +1 -0
  61. package/src/ui/Select/Select.tsx +2 -2
  62. package/src/utils/constants.ts +37 -0
  63. package/src/utils/exportPdf.ts +3 -1
  64. package/src/utils/highlightLinesNetworkPlan.ts +25 -0
  65. package/src/utils/hooks/useI18n.tsx +6 -4
  66. package/src/utils/hooks/useInitialPermalink.tsx +9 -2
  67. package/src/utils/hooks/useMapContext.tsx +9 -0
  68. package/src/utils/sharingGraphqlUtils.ts +1 -1
  69. package/src/utils/translations.ts +12 -1
  70. package/tailwind.config.mjs +3 -1
  71. package/src/ShareMenu/PermalinkButton/PermalinkButton.tsx +0 -62
  72. package/src/ShareMenu/PermalinkButton/index.tsx +0 -1
  73. package/src/icons/Geolocation/airport-14-svgrepo-com.svg +0 -41
@@ -0,0 +1,88 @@
1
+ import { MaplibreStyleLayer } from "mobility-toolbox-js/ol";
2
+ import { memo } from "preact/compat";
3
+ import { useEffect, useMemo } from "preact/hooks";
4
+
5
+ import {
6
+ LNP_GEOPS_FILTER_HIGHLIGHT,
7
+ LNP_LINE_ID_PROP,
8
+ } from "../utils/constants";
9
+ import highlightLinesNetworkPlan from "../utils/highlightLinesNetworkPlan";
10
+ import useMapContext from "../utils/hooks/useMapContext";
11
+
12
+ import type { MaplibreStyleLayerOptions } from "mobility-toolbox-js/ol/layers/MaplibreStyleLayer";
13
+
14
+ function LinesNetworkPlanLayerHighlight(props: MaplibreStyleLayerOptions) {
15
+ const {
16
+ baseLayer,
17
+ featuresInfos,
18
+ lines,
19
+ linesIds,
20
+ linesNetworkPlanLayer,
21
+ map,
22
+ setLinesIds,
23
+ } = useMapContext();
24
+
25
+ const layer = useMemo(() => {
26
+ if (!baseLayer) {
27
+ return null;
28
+ }
29
+ return new MaplibreStyleLayer({
30
+ layersFilter: ({ metadata }) => {
31
+ return metadata?.["geops.filter"]?.startsWith(
32
+ LNP_GEOPS_FILTER_HIGHLIGHT,
33
+ );
34
+ },
35
+ maplibreLayer: baseLayer,
36
+ ...(props || {}),
37
+ });
38
+ }, [baseLayer, props]);
39
+
40
+ useEffect(() => {
41
+ if (!map || !layer) {
42
+ return;
43
+ }
44
+
45
+ map.addLayer(layer);
46
+ return () => {
47
+ map.removeLayer(layer);
48
+ };
49
+ }, [map, layer]);
50
+
51
+ useEffect(() => {
52
+ if (!layer || !featuresInfos?.length || !linesNetworkPlanLayer) {
53
+ return;
54
+ }
55
+ const features =
56
+ featuresInfos.find((featuresInfo) => {
57
+ return featuresInfo.layer === linesNetworkPlanLayer;
58
+ })?.features || [];
59
+
60
+ const ids = [
61
+ ...new Set(
62
+ (features || []).map((f) => {
63
+ return f.get(LNP_LINE_ID_PROP) as string;
64
+ }),
65
+ ),
66
+ ];
67
+ setLinesIds(ids);
68
+ }, [featuresInfos, layer, linesNetworkPlanLayer, setLinesIds]);
69
+
70
+ useEffect(() => {
71
+ if (!layer || !baseLayer?.loaded) {
72
+ return;
73
+ }
74
+ if (linesIds?.length) {
75
+ highlightLinesNetworkPlan(linesIds, baseLayer);
76
+ layer.setVisible(true);
77
+ }
78
+ return () => {
79
+ layer?.setVisible(false);
80
+ // Reset the filter
81
+ highlightLinesNetworkPlan(undefined, baseLayer);
82
+ };
83
+ }, [baseLayer, baseLayer?.loaded, layer, lines, linesIds]);
84
+
85
+ return null;
86
+ }
87
+
88
+ export default memo(LinesNetworkPlanLayerHighlight);
@@ -0,0 +1 @@
1
+ export { default } from "./LinesNetworkPlanLayerHighlight";
@@ -66,10 +66,12 @@ function MapDispatchEvents({
66
66
  : null;
67
67
 
68
68
  // When the ol feature is a cluster
69
- if (json?.properties?.features?.length > 0) {
70
- json.properties.features = json.properties.features.map((feature) => {
71
- return geojson.writeFeatureObject(feature);
72
- });
69
+ if (json?.properties?.clusterLeaves?.length > 0) {
70
+ json.properties.clusterLeaves = json.properties.clusterLeaves.map(
71
+ (feature) => {
72
+ return geojson.writeFeatureObject(feature);
73
+ },
74
+ );
73
75
  }
74
76
  dispatchEvent(node, "mwc:selectedfeature", json);
75
77
  }, [node, selectedFeature]);
@@ -78,11 +78,11 @@ function MapLayout({
78
78
  )}
79
79
  </Map>
80
80
 
81
- <div className="pointer-events-none absolute top-2 bottom-2 left-2 z-10 flex flex-col gap-2 *:pointer-events-auto">
81
+ <div className="pointer-events-none absolute top-2 bottom-2 left-2 z-10 flex flex-col gap-2">
82
82
  {hasToolbar && (
83
83
  <div
84
84
  className={
85
- "relative z-10 w-fit rounded-2xl bg-black/10 p-0 backdrop-blur-sm"
85
+ "pointer-events-none relative z-10 w-fit rounded-2xl bg-black/10 p-0 backdrop-blur-sm *:pointer-events-auto"
86
86
  }
87
87
  >
88
88
  <div
@@ -0,0 +1,116 @@
1
+ import { MapsetLayer as MtbMapsetLayer } from "mobility-toolbox-js/ol";
2
+ import { unByKey } from "ol/Observable";
3
+ import { transformExtent } from "ol/proj";
4
+ import { memo } from "preact/compat";
5
+ import { useEffect, useMemo } from "preact/hooks";
6
+
7
+ import { LAYER_NAME_MAPSET } from "../utils/constants";
8
+ import useMapContext from "../utils/hooks/useMapContext";
9
+
10
+ import type { MapsetLayerOptions } from "mobility-toolbox-js/ol";
11
+
12
+ let moveEndTimeout: ReturnType<typeof setTimeout>;
13
+
14
+ function MapsetLayer(props?: Partial<MapsetLayerOptions>) {
15
+ const {
16
+ apikey,
17
+ baseLayer,
18
+ map,
19
+ mapsetbbox,
20
+ mapsetplanid,
21
+ mapsettenants,
22
+ mapseturl,
23
+ setMapsetLayer,
24
+ } = useMapContext();
25
+
26
+ const layer = useMemo(() => {
27
+ if (!baseLayer || !map) {
28
+ return null;
29
+ }
30
+ return new MtbMapsetLayer({
31
+ apiKey: apikey,
32
+ bbox:
33
+ mapsetbbox?.split(",").map((coord) => {
34
+ return Number(coord.trim());
35
+ }) ||
36
+ transformExtent(
37
+ map.getView()?.calculateExtent(map.getSize()),
38
+ "EPSG:3857",
39
+ "EPSG:4326",
40
+ ),
41
+ mapseturl: mapseturl || undefined,
42
+ name: LAYER_NAME_MAPSET,
43
+ planId: mapsetplanid ?? undefined,
44
+ tenants: mapsettenants?.split(",").map((t) => {
45
+ return t.trim();
46
+ }),
47
+ zoom: map.getView().getZoom(),
48
+ ...(props || {}),
49
+ });
50
+ }, [
51
+ apikey,
52
+ baseLayer,
53
+ map,
54
+ mapsetbbox,
55
+ mapsettenants,
56
+ mapsetplanid,
57
+ mapseturl,
58
+ props,
59
+ ]);
60
+
61
+ useEffect(() => {
62
+ setMapsetLayer?.(layer);
63
+ }, [layer, setMapsetLayer, map]);
64
+
65
+ useEffect(() => {
66
+ if (!map || !layer) {
67
+ return;
68
+ }
69
+ map.addLayer(layer);
70
+
71
+ return () => {
72
+ map.removeLayer(layer);
73
+ };
74
+ }, [map, layer]);
75
+
76
+ useEffect(() => {
77
+ const view = map?.getView();
78
+ if (!view || !layer) {
79
+ return;
80
+ }
81
+ const handleMoveEnd = () => {
82
+ if (mapsetplanid || !layer.get("visible")) {
83
+ return;
84
+ }
85
+ clearTimeout(moveEndTimeout);
86
+ moveEndTimeout = setTimeout(() => {
87
+ const currentBbox = transformExtent(
88
+ view.calculateExtent(map.getSize()),
89
+ "EPSG:3857",
90
+ "EPSG:4326",
91
+ );
92
+ layer.bbox = currentBbox;
93
+ layer.zoom = view.getZoom();
94
+ }, 100);
95
+ };
96
+
97
+ const listeners = [
98
+ layer.on("change:visible", () => {
99
+ if (layer.get("visible")) {
100
+ handleMoveEnd();
101
+ }
102
+ }),
103
+ view.on("change:center", handleMoveEnd),
104
+ view.on("change:resolution", handleMoveEnd),
105
+ ];
106
+
107
+ return () => {
108
+ clearTimeout(moveEndTimeout);
109
+ unByKey(listeners);
110
+ };
111
+ }, [map, layer, mapsetplanid]);
112
+
113
+ return null;
114
+ }
115
+
116
+ export default memo(MapsetLayer);
@@ -0,0 +1 @@
1
+ export { default } from "./MapsetLayer";
@@ -5,8 +5,10 @@ import BaseLayer from "../BaseLayer";
5
5
  import FeaturesInfosListener from "../FeaturesInfosListener";
6
6
  import LayoutState from "../LayoutState";
7
7
  import LinesNetworkPlanLayer from "../LinesNetworkPlanLayer";
8
+ import LinesNetworkPlanLayerHighlight from "../LinesNetworkPlanLayerHighlight";
8
9
  import MapDispatchEvents from "../MapDispatchEvents";
9
10
  import MapLayout from "../MapLayout";
11
+ import MapsetLayer from "../MapsetLayer";
10
12
  import NotificationsLayer from "../NotificationsLayer";
11
13
  import Permalink from "../Permalink";
12
14
  import RealtimeLayer from "../RealtimeLayer";
@@ -26,11 +28,12 @@ import tailwind from "../style.css";
26
28
  // @ts-expect-error bad type definition
27
29
  import style from "./index.css";
28
30
 
31
+ import type { MapsetLayer as MtbMapsetLayer } from "mobility-toolbox-js/ol";
29
32
  import type {
30
33
  MaplibreLayer,
31
34
  MaplibreStyleLayer,
32
- RealtimeLayer as MbtRealtimeLayer,
33
35
  MocoLayer,
36
+ RealtimeLayer as MtbRealtimeLayer,
34
37
  } from "mobility-toolbox-js/ol";
35
38
  import type {
36
39
  LayerGetFeatureInfoResponse,
@@ -58,6 +61,7 @@ function MobilityMap(props: MobilityMapProps) {
58
61
  const [hasGeolocation, setHasGeolocation] = useState<boolean>(false);
59
62
  const [hasLnp, setHasLnp] = useState<boolean>(false);
60
63
  const [hasDetails, setHasDetails] = useState<boolean>(false);
64
+ const [hasMapset, setHasMapset] = useState<boolean>(false);
61
65
  const [hasNotification, setHasNotification] = useState<boolean>(false);
62
66
  const [hasPermalink, setHasPermalink] = useState<boolean>(false);
63
67
  const [hasPrint, setHasPrint] = useState<boolean>(false);
@@ -75,13 +79,16 @@ function MobilityMap(props: MobilityMapProps) {
75
79
  const [stopSequence, setStopSequence] = useState<RealtimeStopSequence>();
76
80
  const [stationsLayer, setStationsLayer] = useState<MaplibreStyleLayer>();
77
81
  const [station, setStation] = useState<RealtimeStation>();
78
- const [realtimeLayer, setRealtimeLayer] = useState<MbtRealtimeLayer>();
82
+ const [realtimeLayer, setRealtimeLayer] = useState<MtbRealtimeLayer>();
79
83
  const [notificationsLayer, setNotificationsLayer] = useState<MocoLayer>();
84
+ const [mapsetLayer, setMapsetLayer] = useState<MtbMapsetLayer>();
80
85
  const [linesNetworkPlanLayer, setLinesNetworkPlanLayer] =
81
86
  useState<MaplibreStyleLayer>();
82
87
  const [map, setMap] = useState<OlMap>();
83
88
  const [stationId, setStationId] = useState<RealtimeStationId>();
84
89
  const [trainId, setTrainId] = useState<RealtimeTrainId>();
90
+ const [linesIds, setLinesIds] = useState<string[]>();
91
+
85
92
  const [featuresInfos, setFeaturesInfos] = useState<
86
93
  LayerGetFeatureInfoResponse[]
87
94
  >([]);
@@ -96,7 +103,7 @@ function MobilityMap(props: MobilityMapProps) {
96
103
  const [previewNotifications, setPreviewNotifications] =
97
104
  useState<SituationType[]>();
98
105
 
99
- const { lang, layers } = props;
106
+ const { lang, layers, lines } = props;
100
107
 
101
108
  // Apply initial visibility of layers
102
109
  useInitialLayersVisiblity(map, layers);
@@ -114,6 +121,7 @@ function MobilityMap(props: MobilityMapProps) {
114
121
  hasGeolocation,
115
122
  hasLayerTree,
116
123
  hasLnp,
124
+ hasMapset,
117
125
  hasNotification,
118
126
  hasPermalink,
119
127
  hasPrint,
@@ -130,8 +138,10 @@ function MobilityMap(props: MobilityMapProps) {
130
138
  isSearchOpen,
131
139
  isShareMenuOpen,
132
140
  isTracking,
141
+ linesIds,
133
142
  linesNetworkPlanLayer,
134
143
  map,
144
+ mapsetLayer,
135
145
  notificationsLayer,
136
146
  permalinkUrlSearchParams,
137
147
  previewNotifications,
@@ -145,6 +155,7 @@ function MobilityMap(props: MobilityMapProps) {
145
155
  setHasGeolocation,
146
156
  setHasLayerTree,
147
157
  setHasLnp,
158
+ setHasMapset,
148
159
  setHasNotification,
149
160
  setHasPermalink,
150
161
  setHasPrint,
@@ -161,8 +172,10 @@ function MobilityMap(props: MobilityMapProps) {
161
172
  setIsSearchOpen,
162
173
  setIsShareMenuOpen,
163
174
  setIsTracking,
175
+ setLinesIds,
164
176
  setLinesNetworkPlanLayer,
165
177
  setMap,
178
+ setMapsetLayer,
166
179
  setNotificationsLayer,
167
180
  setPermalinkUrlSearchParams,
168
181
  setPreviewNotifications,
@@ -186,16 +199,17 @@ function MobilityMap(props: MobilityMapProps) {
186
199
  featuresInfos,
187
200
  featuresInfosHovered,
188
201
  hasDetails,
189
- hasStations,
190
202
  hasGeolocation,
191
203
  hasLayerTree,
192
204
  hasLnp,
205
+ hasMapset,
193
206
  hasNotification,
194
207
  hasPermalink,
195
208
  hasPrint,
196
209
  hasRealtime,
197
210
  hasSearch,
198
211
  hasShare,
212
+ hasStations,
199
213
  hasToolbar,
200
214
  isEmbed,
201
215
  isExportMenuOpen,
@@ -205,8 +219,10 @@ function MobilityMap(props: MobilityMapProps) {
205
219
  isSearchOpen,
206
220
  isShareMenuOpen,
207
221
  isTracking,
222
+ linesIds,
208
223
  linesNetworkPlanLayer,
209
224
  map,
225
+ mapsetLayer,
210
226
  notificationsLayer,
211
227
  permalinkUrlSearchParams,
212
228
  previewNotifications,
@@ -224,6 +240,10 @@ function MobilityMap(props: MobilityMapProps) {
224
240
  i18n.locale(lang);
225
241
  }, [lang]);
226
242
 
243
+ useEffect(() => {
244
+ setLinesIds(lines?.split(","));
245
+ }, [lines]);
246
+
227
247
  return (
228
248
  <I18nContext.Provider value={i18n}>
229
249
  {/* There is a bug in tailwindcss@4 , variables are not imported in the shadow dom
@@ -294,6 +314,8 @@ function MobilityMap(props: MobilityMapProps) {
294
314
  {hasRealtime && <RealtimeLayer />}
295
315
  {hasStations && <StationsLayer />}
296
316
  {hasLnp && <LinesNetworkPlanLayer />}
317
+ {hasLnp && <LinesNetworkPlanLayerHighlight />}
318
+ {hasMapset && <MapsetLayer />}
297
319
 
298
320
  {/* Layout */}
299
321
  <div
@@ -321,7 +343,7 @@ function MobilityMapWithDefaultProps(props: MobilityMapProps) {
321
343
  permalinktemplate || defaultPermalinkTemplate,
322
344
  );
323
345
 
324
- return <MobilityMap {...defaultProps} {...propsFromPermalink} {...props} />;
346
+ return <MobilityMap {...defaultProps} {...props} {...propsFromPermalink} />;
325
347
  }
326
348
 
327
349
  export default memo(MobilityMapWithDefaultProps);
@@ -18,4 +18,42 @@ describe("MobilityMapAttributes", () => {
18
18
  });
19
19
  }
20
20
  });
21
+
22
+ describe("default values are set correctly", () => {
23
+ test("apiKey attribute is properly set", () => {
24
+ expect(attributes.apikey.defaultValue).toBe(
25
+ "5cc87b12d7c5370001c1d655820abcc37dfd4d968d7bab5b2a74a935",
26
+ );
27
+ });
28
+
29
+ test("baselayer attribute is properly set", () => {
30
+ expect(attributes.baselayer.defaultValue).toBe("de.rvf_moco");
31
+ });
32
+
33
+ test("lang attribute is properly set", () => {
34
+ expect(attributes.lang.defaultValue).toBe("de");
35
+ });
36
+
37
+ test("notificationtenant attribute is properly set", () => {
38
+ expect(attributes.notificationtenant.defaultValue).toBe("rvf");
39
+ });
40
+
41
+ test("maxextent attribute is properly set", () => {
42
+ expect(attributes.maxextent.defaultValue).toBe(
43
+ "834896.1809495519,6057089.852937808,940649.6972031617,6173660.451962929",
44
+ );
45
+ });
46
+
47
+ test("permalinktemplate attribute is properly set", () => {
48
+ expect(attributes.permalinktemplate.defaultValue).toBe(
49
+ "#map/{{x}}/{{y}}/{{z}}",
50
+ );
51
+ });
52
+
53
+ test("realtimebboxparameters attribute is properly set", () => {
54
+ expect(attributes.realtimebboxparameters.defaultValue).toBe(
55
+ "line_tags=RVF",
56
+ );
57
+ });
58
+ });
21
59
  });