@geops/rvf-mobility-web-component 0.1.46 → 0.1.47-beta.0

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 (194) hide show
  1. package/.prettierrc.js +3 -1
  2. package/README.md +1 -1
  3. package/doc/package.json +4 -3
  4. package/doc/postcss.config.mjs +1 -1
  5. package/doc/src/app/components/GeopsMobilityDoc.tsx +13 -224
  6. package/doc/src/app/components/GeopsMobilitySearchDoc.tsx +11 -107
  7. package/doc/src/app/components/WebComponentDoc.tsx +45 -56
  8. package/doc/src/app/geops-mobility/page.tsx +7 -2
  9. package/doc/src/app/geops-mobility-search/page.tsx +6 -2
  10. package/doc/src/app/globals.css +47 -27
  11. package/doc/src/app/layout.tsx +4 -2
  12. package/docutils.js +33 -17
  13. package/eslint.config.mjs +28 -34
  14. package/iframe.html +5624 -201
  15. package/index.html +108 -88
  16. package/index.js +2229 -1976
  17. package/input.css +21 -3
  18. package/package.json +37 -40
  19. package/scripts/build.mjs +2 -2
  20. package/scripts/dev.mjs +3 -3
  21. package/search.html +70 -23
  22. package/src/BaseLayer/BaseLayer.tsx +2 -1
  23. package/src/Copyright/Copyright.tsx +4 -2
  24. package/src/DebugDeparture/DebugDeparture.tsx +16 -12
  25. package/src/DebugStop/DebugStop.tsx +2 -2
  26. package/src/Departure/Departure.tsx +2 -3
  27. package/src/EmbedNavigation/DragPanWarning.ts +125 -0
  28. package/src/EmbedNavigation/EmbedNavigation.tsx +52 -0
  29. package/src/EmbedNavigation/index.js +1 -0
  30. package/src/EmbedNavigation/index.tsx +1 -0
  31. package/src/GeolocationButton/GeolocationButton.tsx +11 -35
  32. package/src/GeolocationButton/index.tsx +1 -1
  33. package/src/Map/Map.tsx +5 -3
  34. package/src/MapDispatchEvents/MapDispatchEvents.tsx +78 -0
  35. package/src/MapDispatchEvents/index.tsx +1 -0
  36. package/src/MobilityMap/MobilityMap.tsx +117 -162
  37. package/src/MobilityMap/MobilityMapAttributes.test.ts +21 -0
  38. package/src/MobilityMap/MobilityMapAttributes.ts +243 -0
  39. package/src/MobilityMap/index.tsx +1 -0
  40. package/src/MobilitySearch/MobilitySearch.tsx +35 -0
  41. package/src/MobilitySearch/MobilitySearchAttributes.test.ts +21 -0
  42. package/src/MobilitySearch/MobilitySearchAttributes.ts +68 -0
  43. package/src/MobilitySearch/index.ts +2 -0
  44. package/src/NotificationLayer/NotificationLayer.tsx +27 -4
  45. package/src/Overlay/Overlay.tsx +24 -11
  46. package/src/Permalink/Permalink.tsx +77 -0
  47. package/src/Permalink/index.tsx +1 -0
  48. package/src/RealtimeLayer/RealtimeLayer.tsx +72 -33
  49. package/src/RouteDestination/RouteDestination.tsx +3 -3
  50. package/src/RouteIcon/RouteIcon.tsx +33 -25
  51. package/src/RouteIcon/index.tsx +1 -1
  52. package/src/RouteIdentifier/RouteIdentifer.tsx +6 -5
  53. package/src/RouteInfos/RouteInfos.tsx +7 -3
  54. package/src/RouteSchedule/RouteSchedule.tsx +3 -3
  55. package/src/RouteScheduleFooter/RouteScheduleFooter.tsx +1 -1
  56. package/src/RouteScheduleHeader/RouteScheduleHeader.tsx +7 -29
  57. package/src/RouteStop/RouteStop.tsx +8 -11
  58. package/src/RouteStopDelay/RouteStopDelay.tsx +2 -1
  59. package/src/RouteStopName/RouteStopName.tsx +2 -2
  60. package/src/RouteStopPlatform/RouteStopPlatform.tsx +2 -2
  61. package/src/RouteStopProgress/RouteStopProgress.tsx +2 -1
  62. package/src/RouteStopServices/RouteStopServices.tsx +2 -2
  63. package/src/RouteStopStation/RouteStopStation.tsx +8 -2
  64. package/src/RouteStopTime/RouteStopTime.tsx +2 -1
  65. package/src/RvfButton/RvfButton.tsx +14 -5
  66. package/src/RvfCheckbox/RvfCheckbox.tsx +8 -8
  67. package/src/RvfEmbedNavigation/DragPanWarning.ts +5 -5
  68. package/src/RvfEmbedNavigation/RvfEmbedNavigation.tsx +1 -0
  69. package/src/RvfExportMenu/RvfExportMenu.tsx +14 -12
  70. package/src/RvfExportMenuButton/RvfExportMenuButton.tsx +6 -7
  71. package/src/RvfFeatureDetails/RvfFeatureDetails.tsx +5 -5
  72. package/src/RvfFeatureDetails/RvfLineNetworkDetails/RvfLineNetworkDetails.tsx +164 -138
  73. package/src/RvfFeatureDetails/RvfNotificationDetails/RvfNotificationDetails.tsx +151 -109
  74. package/src/RvfFeatureDetails/RvfSellingPointDetails/RvfSellingPointDetails.tsx +2 -2
  75. package/src/RvfFeatureDetails/RvfSharedMobilityDetail/FloatingVehiclesDetails/FloatingVehiclesDetails.tsx +3 -3
  76. package/src/RvfFeatureDetails/RvfSharedMobilityDetail/RvfSharedMobilityDetails.tsx +8 -6
  77. package/src/RvfFeatureDetails/RvfSharedMobilityDetail/StationDetails/StationDetails.tsx +5 -4
  78. package/src/RvfFeatureDetailsTitle/RvfFeatureDetailsTitle.tsx +81 -0
  79. package/src/RvfFeatureDetailsTitle/index.tsx +1 -0
  80. package/src/RvfFloatingMenu/RvfFloatingMenu.tsx +4 -4
  81. package/src/RvfGeolocationButton/GeolocationButton.tsx +98 -0
  82. package/src/RvfGeolocationButton/index.tsx +1 -0
  83. package/src/RvfIconButton/RvfIconButton.tsx +20 -9
  84. package/src/RvfInputCopy/RvfInputCopy.tsx +8 -8
  85. package/src/RvfLayerTree/RvfLayerTree.tsx +5 -2
  86. package/src/RvfLayerTree/TreeItem/TreeItem.tsx +13 -16
  87. package/src/RvfLayerTree/layersTreeReducer.ts +23 -18
  88. package/src/RvfLayerTreeButton/RvfLayerTreeButton.tsx +6 -6
  89. package/src/RvfLineNetworkPlanLayer/RvfLineNetworkPlanLayer.tsx +2 -1
  90. package/src/RvfLink/RvfLink.tsx +4 -3
  91. package/src/RvfMobilityMap/RvfMobilityMap.tsx +314 -322
  92. package/src/RvfModal/RvfModal.tsx +4 -3
  93. package/src/RvfOverlayContent/RvfOverlayContent.tsx +126 -0
  94. package/src/RvfOverlayContent/index.ts +0 -0
  95. package/src/RvfOverlayHeader/RvfOverlayHeader.tsx +13 -10
  96. package/src/RvfPermalink/RvfPermalink.tsx +2 -2
  97. package/src/RvfPoisLayer/RvfPoisLayer.tsx +2 -1
  98. package/src/RvfRadioButton/RvfRadioButton.tsx +1 -1
  99. package/src/RvfRouteIcon/RvfRouteIcon.tsx +10 -0
  100. package/src/RvfRouteIcon/index.tsx +1 -0
  101. package/src/RvfSearch/RvfSearch.tsx +4 -1
  102. package/src/RvfSearchButton/RvfSearchButton.tsx +27 -0
  103. package/src/RvfSearchButton/index.tsx +1 -0
  104. package/src/RvfSelect/RvfSelect.tsx +7 -5
  105. package/src/RvfSelectedFeatureHighlightLayer/RvfSelectedFeatureHighlightLayer.tsx +1 -2
  106. package/src/RvfSellingPointsLayer/RvfSellingPointsLayer.tsx +2 -1
  107. package/src/RvfShare/RvfPermalinkButton/RvfPermalinkButton.tsx +13 -12
  108. package/src/RvfShare/RvfShare.tsx +11 -10
  109. package/src/RvfShareMenuButton/RvfShareMenuButton.tsx +5 -5
  110. package/src/RvfSharedMobilityLayerGroup/RvfSharedMobilityLayerGroup.tsx +25 -22
  111. package/src/RvfSingleClickListener/RvfSingleClickListener.tsx +46 -31
  112. package/src/RvfTarifZonenLayer/RvfTarifZonenLayer.tsx +2 -1
  113. package/src/RvfTopics/RvfTopics.tsx +6 -5
  114. package/src/RvfZoomButtons/RvfZoomButtons.tsx +3 -3
  115. package/src/ScaleLine/ScaleLine.tsx +5 -4
  116. package/src/ScrollableHandler/ScrollableHandler.tsx +2 -1
  117. package/src/ScrollableHandler/index.tsx +1 -1
  118. package/src/SingleClickListener/SingleClickListener.tsx +47 -4
  119. package/src/Station/Station.tsx +5 -5
  120. package/src/StationName/StationName.tsx +3 -3
  121. package/src/StationServices/StationServices.tsx +3 -3
  122. package/src/StationsLayer/StationsLayer.tsx +5 -4
  123. package/src/StopsSearch/StopsSearch.tsx +115 -84
  124. package/src/WindowMessageListener/WindowMessageListener.tsx +67 -0
  125. package/src/WindowMessageListener/index.tsx +1 -0
  126. package/src/icons/Airport/Airport.tsx +4 -4
  127. package/src/icons/ArrowDown/ArrowDown.tsx +1 -1
  128. package/src/icons/ArrowUp/ArrowUp.tsx +1 -1
  129. package/src/icons/ArrowUpRight/ArrowUpRight.tsx +1 -1
  130. package/src/icons/BarAndRestaurants/BarAndRestaurants.tsx +2 -2
  131. package/src/icons/Bathroom/Bathroom.tsx +1 -1
  132. package/src/icons/Copy/Copy.tsx +1 -1
  133. package/src/icons/Doc/Doc.tsx +1 -1
  134. package/src/icons/Email/Email.tsx +1 -1
  135. package/src/icons/FilePdf/FilePdf.tsx +1 -1
  136. package/src/icons/Geolocation/Geolocation.tsx +3 -5
  137. package/src/icons/Image/Image.tsx +1 -1
  138. package/src/icons/Menu/Menu.tsx +1 -1
  139. package/src/icons/Minus/Minus.tsx +1 -1
  140. package/src/icons/NoRealtime/NoRealtime.tsx +1 -1
  141. package/src/icons/Plus/Plus.tsx +1 -1
  142. package/src/icons/Police/Police.tsx +3 -3
  143. package/src/icons/Share/Share.tsx +1 -1
  144. package/src/icons/Stack/Stack.tsx +1 -1
  145. package/src/icons/Tracking/Tracking.tsx +29 -0
  146. package/src/icons/Tracking/airport-14-svgrepo-com.svg +41 -0
  147. package/src/icons/Tracking/index.tsx +1 -0
  148. package/src/icons/WaitingAreas/WaitingAreas.tsx +1 -1
  149. package/src/icons/WheelChair/WheelChair.tsx +1 -1
  150. package/src/index.tsx +8 -46
  151. package/src/indexDoc.ts +13 -0
  152. package/src/ui/Button/Button.tsx +57 -0
  153. package/src/ui/Button/index.tsx +1 -0
  154. package/src/ui/IconButton/IconButton.tsx +44 -0
  155. package/src/ui/IconButton/index.tsx +1 -0
  156. package/src/utils/MobilityEvent.ts +4 -3
  157. package/src/utils/applyInitialLayerVisibility.ts +3 -3
  158. package/src/utils/centerOnStation.ts +3 -2
  159. package/src/utils/centerOnVehicle.ts +5 -4
  160. package/src/utils/constants.ts +17 -3
  161. package/src/utils/exportPdf.ts +26 -20
  162. package/src/utils/fullTrajectoryStyle.ts +2 -2
  163. package/src/utils/getAllLayers.ts +4 -3
  164. package/src/utils/getDelayColor.test.ts +1 -0
  165. package/src/utils/getDelayColorForVehicle.test.ts +2 -0
  166. package/src/utils/getDelayString.test.ts +3 -0
  167. package/src/utils/getDelayTextForVehicle.test.ts +4 -0
  168. package/src/utils/getFullTrajectoryAndFit.ts +4 -3
  169. package/src/utils/getHoursAndMinutes.test.ts +1 -0
  170. package/src/utils/getLayersAsFlatArray.ts +2 -2
  171. package/src/utils/getLinkByDevice.ts +1 -1
  172. package/src/utils/getMainColorForVehicle.ts +3 -3
  173. package/src/utils/getPermalinkParameters.ts +2 -2
  174. package/src/utils/getStopStatus.test.ts +2 -1
  175. package/src/utils/getStopStatus.ts +1 -1
  176. package/src/utils/getTextForVehicle.ts +1 -1
  177. package/src/utils/hooks/useDeparture.tsx +6 -5
  178. package/src/utils/hooks/useI18n.tsx +6 -4
  179. package/src/utils/hooks/useInitialLayersVisiblity.tsx +2 -1
  180. package/src/utils/hooks/useLayerConfig.tsx +39 -0
  181. package/src/utils/hooks/useMapContext.tsx +30 -18
  182. package/src/utils/hooks/useRouteStop.tsx +3 -2
  183. package/src/utils/hooks/useRvfContext.tsx +11 -3
  184. package/src/utils/hooks/useStation.tsx +2 -1
  185. package/src/utils/hooks/useUpdatePermalink.tsx +25 -24
  186. package/src/utils/hooks/useZoom.tsx +4 -4
  187. package/src/utils/realtimeRVFStyle.ts +5 -4
  188. package/src/utils/sharingGraphqlUtils.ts +3 -2
  189. package/src/utils/sharingStylesUtils.ts +7 -7
  190. package/src/utils/sharingWFSUtils.ts +9 -15
  191. package/tailwind.config.mjs +1 -0
  192. package/tsconfig.json +1 -1
  193. package/doc/tailwind.config.ts +0 -20
  194. package/src/utils/getFeatureInformationTitle.tsx +0 -54
@@ -0,0 +1,243 @@
1
+ //type: "checkbox" | "date" | "select" | "textfield";
2
+
3
+ import {
4
+ DEFAULT_QUERYABLE_LAYERS,
5
+ RVF_EXTENT_3857,
6
+ RVF_LAYERS_NAMES,
7
+ } from "../utils/constants";
8
+
9
+ // const geopsApiLink = `<a href="https://developer.geops.io/">geOps API key</a>`;
10
+ // const geopsMapsApiLink = `<a href="https://developer.geops.io/apis/maps">geOps Maps API</a>`;
11
+ // const geopsStopsApiLink = `<a href="https://developer.geops.io/apis/stops">geOps Stops API</a>`;
12
+ const geopsMocoApiLink = `<a href="https://geops.com/en/solution/disruption-information">geOps MOCO API</a>`;
13
+ const geopsRealtimeApiLink = `<a href="https://developer.geops.io/apis/realtime">geOps Realtime API</a>`;
14
+
15
+ export interface WebComponentAttributeDoc {
16
+ defaultValue?: string;
17
+ description: string;
18
+ type?: "boolean" | undefined;
19
+ }
20
+
21
+ export type MobilityMapAttributeName =
22
+ | "apikey"
23
+ | "baselayer"
24
+ | "center"
25
+ | "details"
26
+ | "embed"
27
+ | "extent"
28
+ | "geolocation"
29
+ | "layers"
30
+ | "layersconfig"
31
+ | "layertree"
32
+ | "mainlink"
33
+ | "mapsurl"
34
+ | "maxextent"
35
+ | "maxzoom"
36
+ | "minzoom"
37
+ | "mots"
38
+ | "notification"
39
+ | "notificationat"
40
+ | "notificationtenant"
41
+ | "notificationurl"
42
+ | "permalink"
43
+ | "print"
44
+ | "queryablelayers"
45
+ | "realtime"
46
+ | "realtimebboxparameters"
47
+ | "realtimetenant"
48
+ | "realtimeurl"
49
+ | "runs"
50
+ | "search"
51
+ | "share"
52
+ | "stopsurl"
53
+ | "tenant"
54
+ | "toolbar"
55
+ | "zoom";
56
+
57
+ export type MobilityMapAttributes = Record<
58
+ MobilityMapAttributeName,
59
+ WebComponentAttributeDoc
60
+ >;
61
+
62
+ const attrs: MobilityMapAttributes = {
63
+ apikey: {
64
+ defaultValue: "5cc87b12d7c5370001c1d655820abcc37dfd4d968d7bab5b2a74a935",
65
+ description: null, //`Your ${geopsApiLink}`,
66
+ },
67
+ baselayer: {
68
+ defaultValue: "de.rvf_moco",
69
+ description: null, //`The style's name from the ${geopsMapsApiLink}. <br/>Ex: base_dark_v2, base_bright_v2, ...`,
70
+ },
71
+ center: {
72
+ description:
73
+ "The center of the map in EPSG:3857 coordinates.<br/>Parameter required if extent is not set.",
74
+ },
75
+ details: {
76
+ defaultValue: "true",
77
+ description:
78
+ "Show shared mobility details in the sidebar when we click on an shared mobility feature.",
79
+ type: "boolean",
80
+ },
81
+ embed: {
82
+ defaultValue: "false",
83
+ description:
84
+ "Toggle the embedded navigation mode.<br/>In this mode zooming with mouse wheel is deactivated and, on touch device, you can only navigate with two finger, a warning message is displayed to warn the user.",
85
+ type: "boolean",
86
+ },
87
+ extent: {
88
+ defaultValue: RVF_EXTENT_3857.join(","),
89
+ description:
90
+ "The map's extent in EPSG:3857 coordinates.<br/>Ex: 831634,5933959,940649,6173660 .<br/>Parameter required if center and zoom are not set.",
91
+ },
92
+ geolocation: {
93
+ defaultValue: "true",
94
+ description: "Toggle the display of the geolocation button or not.",
95
+ type: "boolean",
96
+ },
97
+ layers: {
98
+ defaultValue: null,
99
+ description:
100
+ "A comma separated list of layers's name to make visible on load, others are hidden. If empty, all layers will be hidden except the baselayer.",
101
+ },
102
+ layersconfig: {
103
+ defaultValue: JSON.stringify({
104
+ [RVF_LAYERS_NAMES.liniennetz]: {
105
+ link: {
106
+ href: "https://www.rvf.de/fahrtinfo/netzplan",
107
+ text: "Zum Liniennetzpläne",
108
+ },
109
+ title: "Liniennetzpläne",
110
+ },
111
+ [RVF_LAYERS_NAMES.meldungen]: {
112
+ link: {
113
+ href: "https://moco.dev.geops.io/situation/{{id}}",
114
+ text: "Zum Moco",
115
+ },
116
+ },
117
+ }),
118
+ description: `A JSON string to configure the layers and other components associated to it. See "layers" attributes to find the list of available layers.<br/>
119
+ Definition for a layer :
120
+ <pre style="font-size: 12px; overflow: auto;">{
121
+ liniennetz: {
122
+ link: { // Define the link to display int footer of the details view, if not defined no link is displayed.
123
+ text: "Zum Liniennetzpläne", // The text of the link, if not defined the title is used.
124
+ href: "https://www.rvf.de/fahrtinfo/netzplan", // The url of the link, if not defined no link is displayed.
125
+ },
126
+ title: "Liniennetzpläne", // Text displayed on the layer tree and in the header of the details view.
127
+ }
128
+ <//pre>}`,
129
+ },
130
+ layertree: {
131
+ defaultValue: "true",
132
+ description: "Show/hide the layers tree button in the toolbar.",
133
+ type: "boolean",
134
+ },
135
+ mainlink: {
136
+ defaultValue: "https://www.rvf.de/",
137
+ description: "A link displayed on bottom left of the map.",
138
+ },
139
+ mapsurl: {
140
+ defaultValue: "https://maps.geops.io",
141
+ description: null, //`The ${geopsMapsApiLink} url to use.`,
142
+ },
143
+ maxextent: {
144
+ defaultValue: RVF_EXTENT_3857.join(","),
145
+ description:
146
+ "The maximum extent of the map in EPSG:3857 coordinates.<br/>Ex: 831634,5933959,940649,6173660 .",
147
+ },
148
+ maxzoom: {
149
+ defaultValue: "20",
150
+ description: "The maximal zoom level of the map.",
151
+ },
152
+ minzoom: {
153
+ description: "The minimal zoom level of the map.",
154
+ },
155
+ mots: {
156
+ description: null,
157
+ // "Commas separated list of mots to display on the Realtime layer.<br/>Ex: rail,bus,coach,foot,tram,subway,gondola,funicular,ferry,car .",
158
+ },
159
+ notification: {
160
+ defaultValue: "true",
161
+ description: `Add the notification layer to the map. This layer will display informations about disruptions on the network. Data comes from
162
+ our ${geopsMocoApiLink} .`,
163
+ type: "boolean",
164
+ },
165
+ notificationat: {
166
+ description: null,
167
+ // "An ISO date string used to display active notification at this date in the notification layer. If not defined the current date will be used.<br/>Ex: 2025-08-01T00:00:00Z .",
168
+ },
169
+ notificationtenant: {
170
+ defaultValue: "rvf",
171
+ description: null, // `The ${geopsMocoApiLink} tenant to get the notification from.`,
172
+ },
173
+ notificationurl: {
174
+ defaultValue: "https://moco.dev.geops.io/api/v2/",
175
+ description: null, // `The ${geopsMocoApiLink} url to use.`,
176
+ },
177
+ permalink: {
178
+ defaultValue: "false",
179
+ description:
180
+ "Update some url parameters x,y,z,layers to the current window location. These parameters are used to store the current state of the map. They will be used on page load to configure the web-component.",
181
+ type: "boolean",
182
+ },
183
+ print: {
184
+ defaultValue: "true",
185
+ description: "Show/hide the print button in the toolbar.",
186
+ type: "boolean",
187
+ },
188
+ queryablelayers: {
189
+ defaultValue: DEFAULT_QUERYABLE_LAYERS,
190
+ description:
191
+ "A comma separated list of layers's name. The data of these layers will be queryable by click on the map (see selectedfeature event). If empty, all layers will not be queryable.",
192
+ },
193
+ realtime: {
194
+ defaultValue: "true",
195
+ description: `Add the realtime layer to the map. Data comes from the ${geopsRealtimeApiLink} .`,
196
+ type: "boolean",
197
+ },
198
+ realtimebboxparameters: {
199
+ defaultValue: "line_tags=RVF",
200
+ description: null,
201
+ // "A space separated list of parameters to add to the realtime BBOX request to define custom behavior.<br/>Ex: graph=XXX line_tags=XXX.",
202
+ },
203
+ realtimetenant: {
204
+ description: null, // `The ${geopsRealtimeApiLink} tenant to get the realtime data from.`,
205
+ },
206
+ realtimeurl: {
207
+ defaultValue: "wss://api.geops.io/tracker-ws/v1/ws",
208
+ description: null, //`The ${geopsRealtimeApiLink} url to use.`,
209
+ },
210
+ runs: {
211
+ defaultValue: "false",
212
+ description:
213
+ "Shows the number of trips on a line in the sidebar, use only for debugging.",
214
+ type: "boolean",
215
+ },
216
+ search: {
217
+ defaultValue: "true",
218
+ description: "Toggle the search stops input.",
219
+ type: "boolean",
220
+ },
221
+ share: {
222
+ defaultValue: "true",
223
+ description: "Show/hide the share button in the toolbar.",
224
+ type: "boolean",
225
+ },
226
+ stopsurl: {
227
+ defaultValue: "https://api.geops.io/stops/v1/",
228
+ description: null, // `The ${geopsStopsApiLink} to use.`,
229
+ },
230
+ tenant: {
231
+ description: null, //`The tenant to use by default for all geOps APIs (Stops, Realtime, MOCO ...). Can be override for each API by other XXXXtenant parameters.`,
232
+ },
233
+ toolbar: {
234
+ defaultValue: "false",
235
+ description: "Show/hide the toolbar on the left.",
236
+ type: "boolean",
237
+ },
238
+ zoom: {
239
+ description: "The zoom level of the map.",
240
+ },
241
+ };
242
+
243
+ export default attrs;
@@ -1 +1,2 @@
1
1
  export { default } from "../RvfMobilityMap";
2
+ export { default as MobilityMapAttributes } from "./MobilityMapAttributes";
@@ -0,0 +1,35 @@
1
+ import { memo } from "preact/compat";
2
+
3
+ import StopsSearch from "../StopsSearch/StopsSearch";
4
+ import { I18nContext } from "../utils/hooks/useI18n";
5
+ import i18n from "../utils/i18n";
6
+
7
+ import MobilitySearchAttributes from "./MobilitySearchAttributes";
8
+
9
+ // @ts-expect-error tailwind must be added for the search web component
10
+ import tailwind from "../style.css";
11
+
12
+ import type { StopsSearchProps } from "../StopsSearch/StopsSearch";
13
+
14
+ export type MobilitySearchProps = StopsSearchProps;
15
+
16
+ function MobilitySearch(props: MobilitySearchProps) {
17
+ return (
18
+ <I18nContext.Provider value={i18n}>
19
+ <style>{tailwind}</style>
20
+ <StopsSearch {...props} />
21
+ </I18nContext.Provider>
22
+ );
23
+ }
24
+
25
+ // We creates a wrapper to inject the default props values from MobilityMapAttributes.
26
+ const defaultProps = {};
27
+ Object.entries(MobilitySearchAttributes).forEach(([key]) => {
28
+ defaultProps[key] = MobilitySearchAttributes[key].defaultValue || null;
29
+ });
30
+
31
+ function MobilitySearchWithDefaultProps(props: MobilitySearchProps) {
32
+ return <MobilitySearch {...defaultProps} {...props} />;
33
+ }
34
+
35
+ export default memo(MobilitySearchWithDefaultProps);
@@ -0,0 +1,21 @@
1
+ import attributes from "./MobilitySearchAttributes";
2
+
3
+ describe("MobilityMapAttributes", () => {
4
+ Object.entries(attributes).forEach(([key, value]) => {
5
+ test(`${key} has a description`, () => {
6
+ expect(value.description).toBeDefined();
7
+ });
8
+
9
+ if (value.type === "boolean") {
10
+ test(`${key} has a defaultValue for boolean`, () => {
11
+ expect(value.defaultValue).toMatch(/^(true|false)$/);
12
+ });
13
+ }
14
+
15
+ if (value.defaultValue === "true" || value.defaultValue === "false") {
16
+ test(`${key} is boolean when defaultValue is true or false`, () => {
17
+ expect(value.type).toBe("boolean");
18
+ });
19
+ }
20
+ });
21
+ });
@@ -0,0 +1,68 @@
1
+ import type { WebComponentAttributeDoc } from "../MobilityMap/MobilityMapAttributes";
2
+
3
+ const geopsApiLink = `<a href="https://developer.geops.io/">geOps API key</a>`;
4
+ const geopsStopsApiLink = `<a href="https://developer.geops.io/apis/stops">geOps Stops API</a>`;
5
+
6
+ export type MobilitySearchAttributeName =
7
+ | "apikey"
8
+ | "bbox"
9
+ | "countrycode"
10
+ | "event"
11
+ | "field"
12
+ | "limit"
13
+ | "mots"
14
+ | "onselect"
15
+ | "params"
16
+ | "prefagencies"
17
+ | "reflocation"
18
+ | "url";
19
+
20
+ export type MobilitySearchAttributes = Record<
21
+ MobilitySearchAttributeName,
22
+ WebComponentAttributeDoc
23
+ >;
24
+
25
+ const attrs: MobilitySearchAttributes = {
26
+ apikey: {
27
+ description: `Your ${geopsApiLink}`,
28
+ },
29
+ bbox: {
30
+ description: `The extent where to search the stops (minx,miny,maxx,maxy). See the ${geopsStopsApiLink} documentation.`,
31
+ },
32
+ countrycode: {
33
+ description: "The country code to filter the results (IT, DE, CH ...)",
34
+ },
35
+ event: {
36
+ defaultValue: "mwc:stopssearchselect",
37
+ description: "The event's name to listen to when a stop is selected.",
38
+ },
39
+ field: {
40
+ description: `Which field to look up, default all of them, Possible values:id, name, coords. See the ${geopsStopsApiLink} documentation.`,
41
+ },
42
+ limit: {
43
+ defaultValue: "5",
44
+ description: `The number of suggestions to show. See the ${geopsStopsApiLink} documentation.`,
45
+ },
46
+ mots: {
47
+ description: `Commas separated list of mots used to filter the results (rail, bus, coach, foot, tram, subway, gondola, funicular, ferry, car). See the ${geopsStopsApiLink} documentation.`,
48
+ },
49
+ onselect: {
50
+ description: null, //`Function called when a stop is selected. The function receives the selected stop as parameter.`,
51
+ },
52
+ params: {
53
+ description: `JSON string with additional parameters to pass to the request to the API. Ex: {"{ 'key': 'value' }"}. See the ${geopsStopsApiLink} documentation.`,
54
+ },
55
+ prefagencies: {
56
+ description: `comma seperated list, order chooses which agency will be preferred as
57
+ ident_source (for id and code fields). Possible values: sbb, db. See the ${geopsStopsApiLink} documentation.`,
58
+ },
59
+ reflocation: {
60
+ description: `Coordinates in WGS84 (in lat,lon order) used to rank stops close to this position higher. See the ${geopsStopsApiLink} documentation.`,
61
+ },
62
+ url: {
63
+ defaultValue: "https://api.geops.io/stops/v1/",
64
+ description: `The URL to the ${geopsStopsApiLink}.`,
65
+ },
66
+ };
67
+
68
+ export default attrs;
@@ -0,0 +1,2 @@
1
+ export { default } from "./MobilitySearch";
2
+ export { default as MobilitySearchAttributes } from "./MobilitySearchAttributes";
@@ -1,12 +1,22 @@
1
1
  import { MocoLayer } from "mobility-toolbox-js/ol";
2
- import { MocoLayerOptions } from "mobility-toolbox-js/ol/layers/MocoLayer";
3
2
  import { memo } from "preact/compat";
4
3
  import { useEffect, useMemo } from "preact/hooks";
5
4
 
5
+ import { LAYER_NAME_NOTIFICATION } from "../utils/constants";
6
6
  import useMapContext from "../utils/hooks/useMapContext";
7
7
 
8
- function NotificationLayer(props: MocoLayerOptions) {
9
- const { apikey, baseLayer, map } = useMapContext();
8
+ import type { MocoLayerOptions } from "mobility-toolbox-js/ol";
9
+
10
+ function NotificationLayer(props?: Partial<MocoLayerOptions>) {
11
+ const {
12
+ apikey,
13
+ baseLayer,
14
+ map,
15
+ notificationat,
16
+ notificationtenant,
17
+ notificationurl,
18
+ previewNotifications,
19
+ } = useMapContext();
10
20
 
11
21
  const layer = useMemo(() => {
12
22
  if (!baseLayer) {
@@ -14,10 +24,23 @@ function NotificationLayer(props: MocoLayerOptions) {
14
24
  }
15
25
  return new MocoLayer({
16
26
  apiKey: apikey,
27
+ date: notificationat ? new Date(notificationat) : undefined,
17
28
  maplibreLayer: baseLayer,
29
+ name: LAYER_NAME_NOTIFICATION,
30
+ situations: previewNotifications,
31
+ tenant: notificationtenant,
32
+ url: notificationurl,
18
33
  ...(props || {}),
19
34
  });
20
- }, [apikey, baseLayer, props]);
35
+ }, [
36
+ apikey,
37
+ baseLayer,
38
+ notificationat,
39
+ notificationtenant,
40
+ notificationurl,
41
+ previewNotifications,
42
+ props,
43
+ ]);
21
44
 
22
45
  useEffect(() => {
23
46
  if (!map || !layer) {
@@ -1,15 +1,21 @@
1
- import { JSX, PreactDOMAttributes } from "preact";
2
-
3
- import type { ScrollableHandlerProps } from "../ScrollableHandler";
1
+ import { twMerge } from "tailwind-merge";
4
2
 
5
3
  import ScrollableHandler from "../ScrollableHandler";
6
4
 
5
+ import type { HTMLAttributes, PreactDOMAttributes } from "preact";
6
+
7
+ import type { ScrollableHandlerProps } from "../ScrollableHandler";
8
+
7
9
  export type OverlayProps = {
8
10
  ScrollableHandlerProps?: ScrollableHandlerProps;
9
- } & JSX.HTMLAttributes<HTMLDivElement> &
11
+ } & HTMLAttributes<HTMLDivElement> &
10
12
  PreactDOMAttributes;
11
13
 
12
- function Overlay({ children, ScrollableHandlerProps = {} }: OverlayProps) {
14
+ function Overlay({
15
+ children,
16
+ className,
17
+ ScrollableHandlerProps = {},
18
+ }: OverlayProps) {
13
19
  let hasChildren = !!children;
14
20
  if (Array.isArray(children)) {
15
21
  hasChildren =
@@ -23,18 +29,25 @@ function Overlay({ children, ScrollableHandlerProps = {} }: OverlayProps) {
23
29
  return null;
24
30
  }
25
31
 
32
+ // ${
33
+ // // children
34
+ // // ? "max-h-[70%] min-h-[75px] w-full border-t @lg:w-[350px] @lg:border-t-0 @lg:border-r"
35
+ // // : "max-h-0 min-h-0 @lg:w-0"
36
+ // }
26
37
  return (
27
38
  <div
28
- className={`relative z-50 flex flex-col overflow-hidden bg-white transition-[min-height,max-height] @lg:transition-[width] ${
29
- children
30
- ? "max-h-[70%] min-h-[75px] w-full border-t @lg:h-[100%!important] @lg:max-h-full @lg:w-[350px] @lg:border-r @lg:border-t-0"
31
- : "max-h-0 min-h-0 @lg:w-0"
32
- }`}
39
+ // We set text-base so the clamp works on overlay container, not main
40
+ className={
41
+ (twMerge(
42
+ `pointer-events-auto relative z-50 flex flex-col overflow-hidden bg-white transition-[min-height,max-height] @lg:transition-[width]`,
43
+ ),
44
+ className)
45
+ }
33
46
  >
34
47
  {hasChildren && (
35
48
  <>
36
49
  <ScrollableHandler
37
- className="absolute inset-0 flex h-[65px] touch-none justify-center @lg:hidden"
50
+ className="absolute inset-0 flex h-[65px] touch-none justify-center @lg/main:hidden"
38
51
  style={{ width: "100%" }}
39
52
  {...ScrollableHandlerProps}
40
53
  >
@@ -0,0 +1,77 @@
1
+ import debounce from "lodash.debounce";
2
+ import { getLayersAsFlatArray } from "mobility-toolbox-js/ol";
3
+ import { unByKey } from "ol/Observable";
4
+ import { memo } from "preact/compat";
5
+ import { useCallback, useEffect } from "preact/hooks";
6
+
7
+ import getPermalinkParameters from "../utils/getPermalinkParameters";
8
+ // import { LAYER_PROP_IS_EXPORTING } from "../constants";
9
+ // import getLayersAsFlatArray from "../getLayersAsFlatArray";
10
+ import useMapContext from "../utils/hooks/useMapContext";
11
+
12
+ import type { Map } from "ol";
13
+ import type { EventsKey } from "ol/events";
14
+
15
+ /**
16
+ * This component keeps track of the map's state using URL search parameters: x,y,z or layers visibility.
17
+ * WARNING: This component is not responsible for applying the url parameters, only for updating them.
18
+ *
19
+ */
20
+ const Permalink = ({ replaceState = false }: { replaceState?: boolean }) => {
21
+ const { map, setPermalinkUrlSearchParams } = useMapContext();
22
+
23
+ const updatePermalink = useCallback(
24
+ (currentMap: Map) => {
25
+ // No update when exporting
26
+ // if (map.get(LAYER_PROP_IS_EXPORTING)) {
27
+ // return;
28
+ // }
29
+ const currentUrlParams = new URLSearchParams(window.location.search);
30
+ const urlParams = getPermalinkParameters(currentMap, currentUrlParams);
31
+ urlParams.set("permalink", "true");
32
+ setPermalinkUrlSearchParams(urlParams);
33
+ if (replaceState) {
34
+ window.history.replaceState(null, null, `?${urlParams.toString()}`);
35
+ }
36
+ },
37
+ [replaceState, setPermalinkUrlSearchParams],
38
+ );
39
+
40
+ useEffect(() => {
41
+ let moveEndKey: EventsKey;
42
+ let loadEndKey: EventsKey;
43
+ let changeVisibleKeys: EventsKey[];
44
+ const updatePermalinkDebounced = debounce(updatePermalink, 1000);
45
+
46
+ if (map) {
47
+ updatePermalinkDebounced(map);
48
+
49
+ // Update x,y,z in URL on moveend
50
+ moveEndKey = map?.on("moveend", (evt) => {
51
+ updatePermalinkDebounced(evt.map);
52
+ });
53
+
54
+ // Update layers in permalink on change:visible event
55
+ loadEndKey = map.once("loadend", (evt) => {
56
+ updatePermalinkDebounced(evt.map);
57
+ changeVisibleKeys = getLayersAsFlatArray(
58
+ evt.map.getLayers().getArray(),
59
+ ).map((layer) => {
60
+ return layer.on("change:visible", () => {
61
+ updatePermalinkDebounced(evt.map);
62
+ });
63
+ });
64
+ });
65
+ }
66
+
67
+ return () => {
68
+ unByKey(moveEndKey);
69
+ unByKey(loadEndKey);
70
+ unByKey(changeVisibleKeys);
71
+ };
72
+ }, [map, updatePermalink]);
73
+
74
+ return null;
75
+ };
76
+
77
+ export default memo(Permalink);
@@ -0,0 +1 @@
1
+ export { default } from "./Permalink";