@geops/rvf-mobility-web-component 0.1.64 → 0.1.66

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 (43) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/docutils.js +125 -51
  3. package/index.html +48 -21
  4. package/index.js +291 -234
  5. package/package.json +12 -12
  6. package/search.html +25 -22
  7. package/src/BaseLayer/BaseLayer.tsx +18 -2
  8. package/src/Copyright/Copyright.tsx +2 -2
  9. package/src/Copyright/index.tsx +1 -1
  10. package/src/LayerTree/TreeItem/TreeItem.tsx +1 -1
  11. package/src/LinesNetworkPlanLayerHighlight/LinesNetworkPlanLayerHighlight.tsx +1 -0
  12. package/src/Map/Map.tsx +27 -1
  13. package/src/MapLayout/MapLayout.tsx +1 -1
  14. package/src/MapLayout/index.tsx +1 -1
  15. package/src/MobilityMap/MobilityMap.tsx +5 -11
  16. package/src/MobilityMap/MobilityMapAttributes.ts +8 -5
  17. package/src/MobilitySearch/MobilitySearchAttributes.ts +12 -0
  18. package/src/NotificationDetails/NotificationDetails.tsx +75 -57
  19. package/src/OverlayDetailsHeader/OverlayDetailsHeader.tsx +1 -1
  20. package/src/Permalink/Permalink.tsx +17 -6
  21. package/src/PermalinkInput/PermalinkInput.tsx +4 -1
  22. package/src/RealtimeLayer/index.tsx +1 -1
  23. package/src/RvfCopyright/RvfCopyright.tsx +32 -0
  24. package/src/RvfCopyright/index.tsx +1 -0
  25. package/src/RvfInputCopy/RvfInputCopy.tsx +18 -8
  26. package/src/RvfMapLayout/RvfMapLayout.tsx +198 -0
  27. package/src/RvfMapLayout/index.tsx +1 -0
  28. package/src/RvfMobilityMap/RvfMobilityMap.tsx +10 -580
  29. package/src/RvfRealtimeLayer/RvfRealtimeLayer.tsx +64 -0
  30. package/src/RvfRealtimeLayer/index.tsx +1 -0
  31. package/src/RvfStationsLayer/RvfStationsLayer.tsx +19 -0
  32. package/src/RvfStationsLayer/index.tsx +1 -0
  33. package/src/ShareMenu/ShareMenu.tsx +3 -1
  34. package/src/StationsLayer/index.tsx +1 -1
  35. package/src/ui/InputCopy/InputCopy.tsx +21 -10
  36. package/src/utils/constants.ts +1 -1
  37. package/src/utils/getUrlFromTemplate.test.ts +23 -0
  38. package/src/utils/getUrlFromTemplate.ts +47 -0
  39. package/src/utils/hooks/useI18n.tsx +2 -4
  40. package/src/utils/hooks/useInitialLayersVisiblity.tsx +27 -4
  41. package/src/utils/hooks/useInitialPermalink.tsx +31 -21
  42. package/src/utils/hooks/usePermalink.tsx +25 -0
  43. package/src/utils/translations.ts +4 -0
@@ -1,200 +1,16 @@
1
- import {
2
- type MaplibreLayer,
3
- type MaplibreStyleLayer,
4
- type MapsetLayer as MbtMapsetLayer,
5
- type RealtimeLayer as MbtRealtimeLayer,
6
- type MocoLayer,
7
- } from "mobility-toolbox-js/ol";
1
+ import { type MaplibreStyleLayer } from "mobility-toolbox-js/ol";
8
2
  import { memo } from "preact/compat";
9
- import { useEffect, useMemo, useRef, useState } from "preact/hooks";
10
- import { twMerge } from "tailwind-merge";
3
+ import { useMemo, useState } from "preact/hooks";
11
4
 
12
- import BaseLayer from "../BaseLayer";
13
- import Copyright from "../Copyright";
14
- import EmbedNavigation from "../EmbedNavigation";
15
- import ExportMenuButton from "../ExportMenuButton";
16
- import FeaturesInfosListener from "../FeaturesInfosListener";
17
- import GeolocationButton from "../GeolocationButton";
18
- import LayerTreeButton from "../LayerTreeButton";
19
- import LayoutState from "../LayoutState";
20
- import LinesNetworkPlanLayer from "../LinesNetworkPlanLayer";
21
- import Map from "../Map";
22
- import MapDispatchEvents from "../MapDispatchEvents";
23
- import MapsetLayer from "../MapsetLayer";
5
+ import MobilityMap from "../MobilityMap/MobilityMap";
24
6
  import MobilityMapAttributes from "../MobilityMap/MobilityMapAttributes";
25
- import NotificationsLayer from "../NotificationsLayer";
26
- import Overlay from "../Overlay";
27
- import OverlayContent from "../OverlayContent";
28
- import Permalink from "../Permalink";
29
- import RealtimeLayer from "../RealtimeLayer";
30
- import RvfMainLinkButton from "../RvfMainLinkButton";
31
- import RvfPoisLayer from "../RvfPoisLayer";
32
- import RvfSelectedFeatureHighlightLayer from "../RvfSelectedFeatureHighlightLayer";
33
- import RvfSellingPointsLayer from "../RvfSellingPointsLayer";
34
- import RvfSharedMobilityLayerGroup from "../RvfSharedMobilityLayerGroup";
35
- import RvfTarifZonenLayer from "../RvfTarifZonenLayer";
36
- import ScaleLine from "../ScaleLine";
37
- import Search from "../Search";
38
- import SearchButton from "../SearchButton";
39
- import ShareMenuButton from "../ShareMenuButton";
40
- import SingleClickListener from "../SingleClickListener";
41
- import StationsLayer from "../StationsLayer";
42
- import fullTrajectoryStyle from "../utils/fullTrajectoryStyle";
43
- import getBgColor from "../utils/getBgColor";
44
- import { getRadius } from "../utils/getRadius";
45
- import getTextColor from "../utils/getTextColor";
46
- import { I18nContext } from "../utils/hooks/useI18n";
47
- import useInitialLayersVisiblity from "../utils/hooks/useInitialLayersVisiblity";
48
- import useInitialPermalink from "../utils/hooks/useInitialPermalink";
49
- import { MapContext } from "../utils/hooks/useMapContext";
50
7
  import { RvfContext } from "../utils/hooks/useRvfContext";
51
- import i18n from "../utils/i18n";
52
- import realtimeRVFStyle from "../utils/realtimeRVFStyle";
53
- import WindowMessageListener from "../WindowMessageListener";
54
- import ZoomButtons from "../ZoomButtons";
55
8
 
56
- // @ts-expect-error bad type definition
57
- import tailwind from "../style.css";
58
- // @ts-expect-error bad type definition
59
- import style from "./index.css";
60
-
61
- import type {
62
- LayerGetFeatureInfoResponse,
63
- RealtimeStation,
64
- RealtimeStationId,
65
- RealtimeStopSequence,
66
- RealtimeTrainId,
67
- SituationType,
68
- } from "mobility-toolbox-js/types";
69
- import type { Feature, Map as OlMap } from "ol";
70
9
  import type { Group } from "ol/layer";
71
10
 
72
11
  import type { MobilityMapProps } from "../MobilityMap/MobilityMap";
73
12
 
74
- const PRIORITY_FROM_TYPE = {
75
- bus: 25,
76
- coach: 15,
77
- train: 30,
78
- tram: 20,
79
- };
80
-
81
- export type RvfMobilityMapProps = {
82
- details: string;
83
- embed: string;
84
- layers: string; // list of visible layers on load
85
- layertree: string;
86
- print: string;
87
- queryablelayers: string;
88
- share: string;
89
- toolbar: string;
90
- } & MobilityMapProps;
91
-
92
- const baseLayerProps = {
93
- mapLibreOptions: {
94
- // For printing purpose
95
- maxCanvasSize: [20000, 20000] as [number, number], // remove 4096 limitations
96
- preserveDrawingBuffer: true,
97
- },
98
- };
99
-
100
- const styleProps = {
101
- //fontSize: 16
102
- };
103
-
104
- const scrollableHandlerProps = {
105
- style: { width: "calc(100% - 60px)" },
106
- };
107
-
108
- const realtimeLayerProps = {
109
- fullTrajectoryStyle: fullTrajectoryStyle,
110
- getMotsByZoom: (z: number) => {
111
- if (z < 9) {
112
- return ["rail"];
113
- }
114
- return null;
115
- },
116
- sort: (
117
- { properties: { delay: delayA, type: typeA } },
118
- { properties: { delay: delayB, type: typeB } },
119
- ) => {
120
- if (typeA !== typeB) {
121
- if (PRIORITY_FROM_TYPE[typeA] < PRIORITY_FROM_TYPE[typeB]) {
122
- return -1;
123
- }
124
- return 1;
125
- }
126
-
127
- if (delayA === delayB) {
128
- return 0;
129
- }
130
-
131
- if (delayA < delayB) {
132
- return -1;
133
- }
134
- return 1;
135
- },
136
- style: realtimeRVFStyle,
137
- styleOptions: {
138
- getBgColor: getBgColor,
139
- getMaxRadiusForStrokeAndDelay: () => {
140
- return 4;
141
- },
142
- getMaxRadiusForText: () => {
143
- return 8;
144
- },
145
- getRadius: getRadius,
146
- getTextColor: getTextColor,
147
- },
148
- };
149
-
150
- function RvfMobilityMap(props: RvfMobilityMapProps) {
151
- const eventNodeRef = useRef<HTMLDivElement>();
152
- const [baseLayer, setBaseLayer] = useState<MaplibreLayer>();
153
- const [isFollowing, setIsFollowing] = useState<boolean>(false);
154
- const [isTracking, setIsTracking] = useState<boolean>(false);
155
- const [isEmbed, setIsEmbed] = useState<boolean>(false);
156
- const [hasGeolocation, setHasGeolocation] = useState<boolean>(false);
157
- const [hasLnp, setHasLnp] = useState<boolean>(false);
158
- const [hasDetails, setHasDetails] = useState<boolean>(false);
159
- const [hasMapset, setHasMapset] = useState<boolean>(false);
160
- const [hasNotification, setHasNotification] = useState<boolean>(false);
161
- const [hasPermalink, setHasPermalink] = useState<boolean>(false);
162
- const [hasPrint, setHasPrint] = useState<boolean>(false);
163
- const [hasRealtime, setHasRealtime] = useState<boolean>(false);
164
- const [hasSearch, setHasSearch] = useState<boolean>(false);
165
- const [hasStations, setHasStations] = useState<boolean>(false);
166
- const [hasToolbar, setHasToolbar] = useState<boolean>(false);
167
- const [hasShare, setHasShare] = useState<boolean>(false);
168
- const [hasLayerTree, setHasLayerTree] = useState<boolean>(false);
169
- const [isOverlayOpen, setIsOverlayOpen] = useState<boolean>(false);
170
- const [isExportMenuOpen, setIsExportMenuOpen] = useState<boolean>(false);
171
- const [isShareMenuOpen, setIsShareMenuOpen] = useState<boolean>(false);
172
- const [isLayerTreeOpen, setIsLayerTreeOpen] = useState<boolean>(false);
173
- const [isSearchOpen, setIsSearchOpen] = useState<boolean>(false);
174
- const [stopSequence, setStopSequence] = useState<RealtimeStopSequence>();
175
- const [stationsLayer, setStationsLayer] = useState<MaplibreStyleLayer>();
176
- const [station, setStation] = useState<RealtimeStation>();
177
- const [realtimeLayer, setRealtimeLayer] = useState<MbtRealtimeLayer>();
178
- const [notificationsLayer, setNotificationsLayer] = useState<MocoLayer>();
179
- const [linesNetworkPlanLayer, setLinesNetworkPlanLayer] =
180
- useState<MaplibreStyleLayer>();
181
- const [mapsetLayer, setMapsetLayer] = useState<MbtMapsetLayer>();
182
-
183
- const [map, setMap] = useState<OlMap>();
184
- const [stationId, setStationId] = useState<RealtimeStationId>();
185
- const [trainId, setTrainId] = useState<RealtimeTrainId>();
186
- const [linesIds, setLinesIds] = useState<string[]>();
187
- const [featuresInfos, setFeaturesInfos] = useState<
188
- LayerGetFeatureInfoResponse[]
189
- >([]);
190
- const [featuresInfosHovered, setFeaturesInfosHovered] = useState<
191
- LayerGetFeatureInfoResponse[]
192
- >([]);
193
- const [selectedFeature, setSelectedFeature] = useState<Feature>();
194
- const [selectedFeatures, setSelectedFeatures] = useState<Feature[]>();
195
-
196
- const [permalinkUrlSearchParams, setPermalinkUrlSearchParams] =
197
- useState<URLSearchParams>();
13
+ function RvfMobilityMap(props: MobilityMapProps) {
198
14
  const [sellingPointsLayer, setSellingPointsLayer] =
199
15
  useState<MaplibreStyleLayer>();
200
16
  const [tarifZonenLayer, setTarifZonenLayer] = useState<MaplibreStyleLayer>();
@@ -202,141 +18,6 @@ function RvfMobilityMap(props: RvfMobilityMapProps) {
202
18
  const [sharedMobilityLayerGroup, setSharedMobilityLayerGroup] =
203
19
  useState<Group>();
204
20
 
205
- const [previewNotifications, setPreviewNotifications] =
206
- useState<SituationType[]>();
207
-
208
- const { lang, layers, mainlink } = props;
209
-
210
- // Apply initial visibility of layers
211
- useInitialLayersVisiblity(map, layers);
212
-
213
- const mapContextValue = useMemo(() => {
214
- return {
215
- // MobilityMapProps
216
- ...props,
217
- // MapContextProps
218
- baseLayer,
219
- featuresInfos,
220
- featuresInfosHovered,
221
- hasDetails,
222
- hasGeolocation,
223
- hasLayerTree,
224
- hasLnp,
225
- hasMapset,
226
- hasNotification,
227
- hasPermalink,
228
- hasPrint,
229
- hasRealtime,
230
- hasSearch,
231
- hasShare,
232
- hasStations,
233
- hasToolbar,
234
- isEmbed,
235
- isExportMenuOpen,
236
- isFollowing,
237
- isLayerTreeOpen,
238
- isOverlayOpen,
239
- isSearchOpen,
240
- isShareMenuOpen,
241
- isTracking,
242
- linesIds,
243
- linesNetworkPlanLayer,
244
- map,
245
- mapsetLayer,
246
- notificationsLayer,
247
- permalinkUrlSearchParams,
248
- previewNotifications,
249
- realtimeLayer,
250
- selectedFeature,
251
- selectedFeatures,
252
- setBaseLayer,
253
- setFeaturesInfos,
254
- setFeaturesInfosHovered,
255
- setHasDetails,
256
- setHasGeolocation,
257
- setHasLayerTree,
258
- setHasLnp,
259
- setHasMapset,
260
- setHasNotification,
261
- setHasPermalink,
262
- setHasPrint,
263
- setHasRealtime,
264
- setHasSearch,
265
- setHasShare,
266
- setHasStations,
267
- setHasToolbar,
268
- setIsEmbed,
269
- setIsExportMenuOpen,
270
- setIsFollowing,
271
- setIsLayerTreeOpen,
272
- setIsOverlayOpen,
273
- setIsSearchOpen,
274
- setIsShareMenuOpen,
275
- setIsTracking,
276
- setLinesIds,
277
- setLinesNetworkPlanLayer,
278
- setMap,
279
- setMapsetLayer,
280
- setNotificationsLayer,
281
- setPermalinkUrlSearchParams,
282
- setPreviewNotifications,
283
- setRealtimeLayer,
284
- setSelectedFeature,
285
- setSelectedFeatures,
286
- setStation,
287
- setStationId,
288
- setStationsLayer,
289
- setStopSequence,
290
- setTrainId,
291
- station,
292
- stationId,
293
- stationsLayer,
294
- stopSequence,
295
- trainId,
296
- };
297
- }, [
298
- props,
299
- baseLayer,
300
- featuresInfos,
301
- featuresInfosHovered,
302
- hasDetails,
303
- hasGeolocation,
304
- hasLayerTree,
305
- hasLnp,
306
- hasMapset,
307
- hasNotification,
308
- hasPermalink,
309
- hasPrint,
310
- hasRealtime,
311
- hasSearch,
312
- hasShare,
313
- hasStations,
314
- hasToolbar,
315
- isEmbed,
316
- isExportMenuOpen,
317
- isFollowing,
318
- isLayerTreeOpen,
319
- isOverlayOpen,
320
- isSearchOpen,
321
- isShareMenuOpen,
322
- isTracking,
323
- linesIds,
324
- linesNetworkPlanLayer,
325
- map,
326
- mapsetLayer,
327
- notificationsLayer,
328
- permalinkUrlSearchParams,
329
- previewNotifications,
330
- realtimeLayer,
331
- selectedFeature,
332
- selectedFeatures,
333
- station,
334
- stationId,
335
- stationsLayer,
336
- stopSequence,
337
- trainId,
338
- ]);
339
-
340
21
  const rvfContextValue = useMemo(() => {
341
22
  return {
342
23
  poisLayer,
@@ -355,258 +36,15 @@ function RvfMobilityMap(props: RvfMobilityMapProps) {
355
36
  tarifZonenLayer,
356
37
  ]);
357
38
 
358
- const copyrightOptions = useMemo(() => {
359
- return {
360
- format: (copyrights) => {
361
- const newCopyrights = [];
362
- let alreadyAGeopsLink = false;
363
- copyrights.forEach((copyright) => {
364
- if (/geops/i.test(copyright)) {
365
- // Hack until all geOps tiles are the same
366
- // Currently there is some geops.com or geops.ch links
367
- if (!alreadyAGeopsLink) {
368
- alreadyAGeopsLink = true;
369
- newCopyrights.push(copyright);
370
- }
371
- } else if (!/(sbb|rvf)/i.test(copyright)) {
372
- newCopyrights.push(copyright);
373
- }
374
- });
375
-
376
- return newCopyrights.join("&nbsp;|&nbsp;");
377
- },
378
- };
379
- }, []);
380
-
381
- const stationsLayerProps = useMemo(() => {
382
- return {
383
- layersFilter: ({ metadata }) => {
384
- return metadata?.["general.filter"] === "stations";
385
- },
386
- };
387
- }, []);
388
-
389
- useEffect(() => {
390
- i18n.locale(lang);
391
- }, [lang]);
392
-
393
39
  return (
394
- <I18nContext.Provider value={i18n}>
395
- {/* There is a bug in tailwindcss@4 , variables are not imported in the shadow dom
396
- see https://github.com/tailwindlabs/tailwindcss/issues/15005*/}
397
- <style>
398
- {`:host {
399
- --tw-divide-y-reverse: 0;
400
- --tw-border-style: solid;
401
- --tw-font-weight: initial;
402
- --tw-tracking: initial;
403
- --tw-translate-x: 0;
404
- --tw-translate-y: 0;
405
- --tw-translate-z: 0;
406
- --tw-rotate-x: rotateX(0);
407
- --tw-rotate-y: rotateY(0);
408
- --tw-rotate-z: rotateZ(0);
409
- --tw-skew-x: skewX(0);
410
- --tw-skew-y: skewY(0);
411
- --tw-space-x-reverse: 0;
412
- --tw-gradient-position: initial;
413
- --tw-gradient-from: #0000;
414
- --tw-gradient-via: #0000;
415
- --tw-gradient-to: #0000;
416
- --tw-gradient-stops: initial;
417
- --tw-gradient-via-stops: initial;
418
- --tw-gradient-from-position: 0%;
419
- --tw-gradient-via-position: 50%;
420
- --tw-gradient-to-position: 100%;
421
- --tw-shadow: 0 0 #0000;
422
- --tw-shadow-color: initial;
423
- --tw-inset-shadow: 0 0 #0000;
424
- --tw-inset-shadow-color: initial;
425
- --tw-ring-color: initial;
426
- --tw-ring-shadow: 0 0 #0000;
427
- --tw-inset-ring-color: initial;
428
- --tw-inset-ring-shadow: 0 0 #0000;
429
- --tw-ring-inset: initial;
430
- --tw-ring-offset-width: 0px;
431
- --tw-ring-offset-color: #fff;
432
- --tw-ring-offset-shadow: 0 0 #0000;
433
- --tw-blur: initial;
434
- --tw-brightness: initial;
435
- --tw-contrast: initial;
436
- --tw-grayscale: initial;
437
- --tw-hue-rotate: initial;
438
- --tw-invert: initial;
439
- --tw-opacity: initial;
440
- --tw-saturate: initial;
441
- --tw-sepia: initial;
442
- --tw-drop-shadow: initial;
443
- --tw-duration: initial;
444
- --tw-ease: initial;
445
- }`}
446
- </style>
447
- <style>{tailwind}</style>
448
- <style>{style}</style>
449
- <MapContext.Provider value={mapContextValue}>
450
- <RvfContext.Provider value={rvfContextValue}>
451
- <LayoutState />
452
- <Permalink replaceState={hasPermalink} />
453
- <MapDispatchEvents node={eventNodeRef.current} wcAttributes={props} />
454
- <WindowMessageListener eventNode={eventNodeRef.current} />
455
- <SingleClickListener />
456
- <FeaturesInfosListener />
457
-
458
- <div
459
- className="@container/main relative size-full overflow-hidden font-sans"
460
- ref={eventNodeRef}
461
- style={styleProps}
462
- >
463
- <div className="relative flex size-full flex-col text-base @lg/main:flex-row-reverse">
464
- <Map className="relative flex-1 overflow-visible">
465
- <BaseLayer {...baseLayerProps} />
466
- {isEmbed && <EmbedNavigation />}
467
- {hasNotification && <NotificationsLayer />}
468
- <RvfSelectedFeatureHighlightLayer />
469
- {hasRealtime && <RealtimeLayer {...realtimeLayerProps} />}
470
- <StationsLayer minZoom={10} {...stationsLayerProps} />
471
- <RvfTarifZonenLayer />
472
- <RvfSellingPointsLayer />
473
- {hasLnp && <LinesNetworkPlanLayer />}
474
-
475
- {hasMapset && <MapsetLayer />}
476
-
477
- <RvfPoisLayer />
478
- <RvfSharedMobilityLayerGroup />
479
- {mainlink && (
480
- <RvfMainLinkButton className="absolute inset-x-2 bottom-8 z-10" />
481
- )}
482
-
483
- <div className="pointer-events-none absolute inset-x-2 bottom-2 z-10 flex items-end justify-between gap-2 text-[10px]">
484
- <ScaleLine className="bg-slate-50/70" />
485
- <Copyright
486
- className="pointer-events-auto bg-slate-50/70"
487
- options={copyrightOptions}
488
- />
489
- </div>
490
- <div className="absolute top-2 right-2 z-10 flex">
491
- {hasGeolocation && (
492
- <GeolocationButton title={"Geolokalisierung"} />
493
- )}
494
- </div>
495
- <div className="absolute right-2 bottom-10 z-10 flex flex-col justify-between gap-2">
496
- <ZoomButtons />
497
- </div>
498
-
499
- {!hasToolbar && hasSearch && (
500
- <div
501
- className={twMerge(
502
- "absolute top-2 right-2 left-2 z-10 max-w-96",
503
- isOverlayOpen && "@lg:left-68",
504
- )}
505
- >
506
- <Search />
507
- </div>
508
- )}
509
- </Map>
510
-
511
- <div className="pointer-events-none absolute top-2 bottom-2 left-2 z-10 flex flex-col gap-2">
512
- {hasToolbar && (
513
- <div
514
- className={
515
- "pointer-events-none relative z-10 w-fit rounded-2xl bg-black/10 p-0 backdrop-blur-sm *:pointer-events-auto"
516
- }
517
- // className="w-fit rounded-2xl bg-black/10 p-1 backdrop-blur-sm">
518
- >
519
- {hasSearch && (
520
- <div
521
- className={twMerge(
522
- "absolute top-12 left-0 w-0 p-0 opacity-0 transition-all @sm:top-0 @sm:left-[calc(100%-43px)] @md:left-[calc(100%-47px)]",
523
- isSearchOpen ? "w-64 opacity-100" : "",
524
- )}
525
- >
526
- <Search
527
- className={
528
- "border-grey @container m-0 h-[40px] rounded-2xl border p-2 px-4 text-base @sm/main:h-[44px] @sm/main:rounded-l-none @sm/main:rounded-r-2xl @md/main:h-[48px]"
529
- }
530
- inputClassName="h-6 text-base"
531
- inputContainerClassName="border-none"
532
- resultClassName="text-base **:hover:cursor-pointer hover:text-red-500 p-2"
533
- resultsContainerClassName="@container rounded-b-2xl max-h-[200px] overflow-y-auto border border-grey border-t-0 "
534
- withResultsClassName="text-base !rounded-b-none"
535
- />
536
- </div>
537
- )}
538
-
539
- <div
540
- className={twMerge(
541
- "border-grey relative flex gap-[1px] overflow-hidden rounded-2xl border @sm/main:h-[44px] @md/main:h-[48px]",
542
- "*:size-[38px] *:rounded-none *:border-none *:@sm/main:size-[42px] *:@md/main:!size-[46px]",
543
- "*:first:!rounded-l-2xl",
544
- "*:last:!rounded-r-2xl",
545
- isSearchOpen
546
- ? "@sm:rounded-r-none @sm:border-r-0 @sm:*:last:!rounded-r-none @sm:*:last:border-r-0"
547
- : "",
548
- )}
549
- >
550
- {hasPrint && <ExportMenuButton />}
551
- {hasShare && <ShareMenuButton />}
552
- {hasLayerTree && <LayerTreeButton />}
553
- {hasSearch && <SearchButton />}
554
- </div>
555
- </div>
556
- )}
557
-
558
- {/* Desktop (>= lg) */}
559
- <div
560
- className={twMerge(
561
- "pointer-events-none flex w-0 flex-1 flex-col overflow-hidden rounded-2xl",
562
- isOverlayOpen ? "@lg:min-w-[320px]" : "p-0",
563
- )}
564
- style={{ containerType: "normal" }}
565
- >
566
- <Overlay
567
- className={
568
- "border-grey @container/overlay pointer-events-auto relative hidden flex-col overflow-hidden rounded-2xl border bg-white text-base shadow-lg @lg:flex"
569
- }
570
- ScrollableHandlerProps={scrollableHandlerProps}
571
- >
572
- <OverlayContent
573
- hasDetails={hasDetails}
574
- hasLayerTree={hasLayerTree}
575
- hasPrint={hasPrint}
576
- hasRealtime={hasRealtime}
577
- hasSearch={false}
578
- hasShare={hasShare}
579
- />
580
- </Overlay>
581
- </div>
582
- </div>
583
-
584
- {/* Mobile */}
585
- <Overlay
586
- className={
587
- isOverlayOpen
588
- ? "absolute bottom-0 z-20 flex max-h-[70%] min-h-[75px] w-full flex-col border-t bg-white @lg:hidden"
589
- : "@lg:hidden"
590
- }
591
- ScrollableHandlerProps={scrollableHandlerProps}
592
- >
593
- <OverlayContent
594
- hasDetails={hasDetails}
595
- hasLayerTree={hasLayerTree}
596
- hasPrint={hasPrint}
597
- hasRealtime={hasRealtime}
598
- hasSearch={false} // The search could be in the overlay but we decide to put it in the toolbar for better UX
599
- hasShare={hasShare}
600
- />
601
- </Overlay>
602
- </div>
603
- </div>
604
- </RvfContext.Provider>
605
- </MapContext.Provider>
606
- </I18nContext.Provider>
40
+ <RvfContext.Provider value={rvfContextValue}>
41
+ <MobilityMap {...props} />
42
+ </RvfContext.Provider>
607
43
  );
608
44
  }
609
45
 
46
+ const MemoRvFMobilityMap = memo(RvfMobilityMap);
47
+
610
48
  // We creates a wrapper to inject the default props values from MobilityMapAttributes.
611
49
  const defaultProps: Partial<MobilityMapProps> = {};
612
50
  Object.entries(MobilityMapAttributes).forEach(([key]) => {
@@ -614,15 +52,7 @@ Object.entries(MobilityMapAttributes).forEach(([key]) => {
614
52
  });
615
53
 
616
54
  function MobilityMapWithDefaultProps(props: MobilityMapProps) {
617
- // Apply initial value from permalink, only x,y,z
618
- const { permalinktemplate } = props;
619
- const { permalinktemplate: defaultPermalinkTemplate } = defaultProps;
620
- const propsFromPermalink = useInitialPermalink(
621
- permalinktemplate || defaultPermalinkTemplate,
622
- );
623
- return (
624
- <RvfMobilityMap {...defaultProps} {...props} {...propsFromPermalink} />
625
- );
55
+ return <MemoRvFMobilityMap {...defaultProps} {...props} />;
626
56
  }
627
57
 
628
58
  export default memo(MobilityMapWithDefaultProps);
@@ -0,0 +1,64 @@
1
+ import { memo } from "preact/compat";
2
+
3
+ import RealtimeLayer from "../RealtimeLayer/RealtimeLayer";
4
+ import fullTrajectoryStyle from "../utils/fullTrajectoryStyle";
5
+ import getBgColor from "../utils/getBgColor";
6
+ import { getRadius } from "../utils/getRadius";
7
+ import getTextColor from "../utils/getTextColor";
8
+ import realtimeRVFStyle from "../utils/realtimeRVFStyle";
9
+
10
+ import type { RealtimeLayerOptions } from "mobility-toolbox-js/ol";
11
+
12
+ const PRIORITY_FROM_TYPE = {
13
+ bus: 25,
14
+ coach: 15,
15
+ train: 30,
16
+ tram: 20,
17
+ };
18
+
19
+ const defaultProps: Partial<RealtimeLayerOptions> = {
20
+ fullTrajectoryStyle: fullTrajectoryStyle,
21
+ getMotsByZoom: (z: number) => {
22
+ if (z < 9) {
23
+ return ["rail"];
24
+ }
25
+ return null;
26
+ },
27
+ sort: (
28
+ { properties: { delay: delayA, type: typeA } },
29
+ { properties: { delay: delayB, type: typeB } },
30
+ ) => {
31
+ if (typeA !== typeB) {
32
+ if (PRIORITY_FROM_TYPE[typeA] < PRIORITY_FROM_TYPE[typeB]) {
33
+ return -1;
34
+ }
35
+ return 1;
36
+ }
37
+
38
+ if (delayA === delayB) {
39
+ return 0;
40
+ }
41
+
42
+ if (delayA < delayB) {
43
+ return -1;
44
+ }
45
+ return 1;
46
+ },
47
+ style: realtimeRVFStyle,
48
+ styleOptions: {
49
+ getBgColor: getBgColor,
50
+ getMaxRadiusForStrokeAndDelay: () => {
51
+ return 4;
52
+ },
53
+ getMaxRadiusForText: () => {
54
+ return 8;
55
+ },
56
+ getRadius: getRadius,
57
+ getTextColor: getTextColor,
58
+ },
59
+ };
60
+ function RvfRealtimeLayer(props: Partial<RealtimeLayerOptions>) {
61
+ return <RealtimeLayer {...defaultProps} {...props} />;
62
+ }
63
+
64
+ export default memo(RvfRealtimeLayer);
@@ -0,0 +1 @@
1
+ export { default } from "./RvfRealtimeLayer";