@geops/rvf-mobility-web-component 0.1.8

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 (212) hide show
  1. package/.fixpackrc +21 -0
  2. package/.husky/commit-msg +1 -0
  3. package/.husky/post-checkout +1 -0
  4. package/.husky/post-merge +1 -0
  5. package/.husky/post-rebase +1 -0
  6. package/.husky/pre-commit +1 -0
  7. package/.lintstagedrc.js +12 -0
  8. package/.nvmrc +1 -0
  9. package/.prettierrc.js +1 -0
  10. package/CHANGELOG.md +183 -0
  11. package/Logo.svg +10 -0
  12. package/README.md +179 -0
  13. package/__mocks__/dataurl.js +11 -0
  14. package/__mocks__/mapbox-gl.js +19 -0
  15. package/commitlint.config.cjs +1 -0
  16. package/doc/.eslintrc.json +3 -0
  17. package/doc/.fixpackrc +21 -0
  18. package/doc/.prettierrc +1 -0
  19. package/doc/README.md +14 -0
  20. package/doc/declarations.d.ts +6 -0
  21. package/doc/next.config.mjs +4 -0
  22. package/doc/package.json +43 -0
  23. package/doc/postcss.config.mjs +8 -0
  24. package/doc/public/README.md +1 -0
  25. package/doc/src/app/components/GeopsAPIKeyLink.tsx +6 -0
  26. package/doc/src/app/components/GeopsAPIsLink.tsx +6 -0
  27. package/doc/src/app/components/GeopsMapsAPILink.tsx +8 -0
  28. package/doc/src/app/components/GeopsMobility.tsx +9 -0
  29. package/doc/src/app/components/GeopsMobilityDoc.tsx +231 -0
  30. package/doc/src/app/components/GeopsMobilitySearch.tsx +10 -0
  31. package/doc/src/app/components/GeopsMobilitySearchDoc.tsx +129 -0
  32. package/doc/src/app/components/GeopsRealtimeAPILink.tsx +10 -0
  33. package/doc/src/app/components/GeopsStopsAPILink.tsx +8 -0
  34. package/doc/src/app/components/Link.tsx +9 -0
  35. package/doc/src/app/components/WebComponentDoc.tsx +296 -0
  36. package/doc/src/app/favicon.ico +0 -0
  37. package/doc/src/app/geops-mobility/page.tsx +6 -0
  38. package/doc/src/app/geops-mobility-search/page.tsx +7 -0
  39. package/doc/src/app/globals.css +38 -0
  40. package/doc/src/app/hooks/useAttrFromUrlParams.ts +21 -0
  41. package/doc/src/app/hooks/useIsFullScreen.ts +14 -0
  42. package/doc/src/app/hooks/usePublicKey.ts +21 -0
  43. package/doc/src/app/layout.tsx +51 -0
  44. package/doc/src/app/page.tsx +86 -0
  45. package/doc/src/geops-ui.ts +3 -0
  46. package/doc/tailwind.config.ts +20 -0
  47. package/doc/tsconfig.json +40 -0
  48. package/eslint.config.mjs +40 -0
  49. package/favicon.ico +0 -0
  50. package/global.d.ts +4 -0
  51. package/iframe.html +34 -0
  52. package/index.html +276 -0
  53. package/index.js +2162 -0
  54. package/input.css +34 -0
  55. package/jest-setup.js +4 -0
  56. package/jest.config.js +17 -0
  57. package/package.json +80 -0
  58. package/scripts/build.mjs +16 -0
  59. package/scripts/dev.mjs +26 -0
  60. package/search.html +144 -0
  61. package/src/BaseLayer/BaseLayer.tsx +36 -0
  62. package/src/BaseLayer/index.tsx +1 -0
  63. package/src/Copyright/Copyright.tsx +54 -0
  64. package/src/Copyright/index.css +3 -0
  65. package/src/Copyright/index.tsx +1 -0
  66. package/src/DebugDeparture/DebugDeparture.tsx +116 -0
  67. package/src/DebugDeparture/index.tsx +1 -0
  68. package/src/DebugStop/DebugStop.tsx +47 -0
  69. package/src/DebugStop/index.tsx +1 -0
  70. package/src/Departure/Departure.tsx +55 -0
  71. package/src/Departure/index.tsx +1 -0
  72. package/src/GeolocationButton/GeolocationButton.tsx +81 -0
  73. package/src/GeolocationButton/index.tsx +1 -0
  74. package/src/Map/Map.tsx +89 -0
  75. package/src/Map/index.tsx +1 -0
  76. package/src/MobilityMap/MobilityMap.tsx +259 -0
  77. package/src/MobilityMap/index.css +13 -0
  78. package/src/MobilityMap/index.tsx +1 -0
  79. package/src/NotificationLayer/NotificationLayer.tsx +156 -0
  80. package/src/NotificationLayer/index.tsx +1 -0
  81. package/src/NotificationLayer/notificationUtils.ts +191 -0
  82. package/src/Overlay/Overlay.tsx +57 -0
  83. package/src/Overlay/index.tsx +1 -0
  84. package/src/RealtimeLayer/RealtimeLayer.tsx +230 -0
  85. package/src/RealtimeLayer/index.tsx +1 -0
  86. package/src/RouteDestination/RouteDestination.test.tsx +13 -0
  87. package/src/RouteDestination/RouteDestination.tsx +15 -0
  88. package/src/RouteDestination/index.tsx +1 -0
  89. package/src/RouteIcon/RouteIcon.tsx +66 -0
  90. package/src/RouteIcon/index.tsx +1 -0
  91. package/src/RouteIdentifier/RouteIdentifer.tsx +35 -0
  92. package/src/RouteIdentifier/index.tsx +1 -0
  93. package/src/RouteInfos/RouteInfos.tsx +22 -0
  94. package/src/RouteInfos/index.tsx +1 -0
  95. package/src/RouteSchedule/RouteSchedule.tsx +69 -0
  96. package/src/RouteSchedule/firstStation.png +0 -0
  97. package/src/RouteSchedule/index.tsx +1 -0
  98. package/src/RouteSchedule/lastStation.png +0 -0
  99. package/src/RouteSchedule/line.png +0 -0
  100. package/src/RouteSchedule/station.png +0 -0
  101. package/src/RouteScheduleFooter/RouteScheduleFooter.tsx +44 -0
  102. package/src/RouteScheduleFooter/index.tsx +1 -0
  103. package/src/RouteScheduleHeader/RouteScheduleHeader.tsx +58 -0
  104. package/src/RouteScheduleHeader/index.tsx +1 -0
  105. package/src/RouteStop/RouteStop.tsx +121 -0
  106. package/src/RouteStop/index.tsx +1 -0
  107. package/src/RouteStopDelay/RouteStopDelay.tsx +36 -0
  108. package/src/RouteStopDelay/index.tsx +1 -0
  109. package/src/RouteStopName/RouteStopName.tsx +24 -0
  110. package/src/RouteStopName/index.tsx +1 -0
  111. package/src/RouteStopPlatform/RouteStopPlatform.tsx +29 -0
  112. package/src/RouteStopPlatform/index.tsx +1 -0
  113. package/src/RouteStopProgress/RouteStopProgress.tsx +101 -0
  114. package/src/RouteStopProgress/index.tsx +1 -0
  115. package/src/RouteStopServices/RouteStopServices.tsx +26 -0
  116. package/src/RouteStopServices/index.tsx +1 -0
  117. package/src/RouteStopStation/RouteStopStation.tsx +32 -0
  118. package/src/RouteStopStation/index.tsx +1 -0
  119. package/src/RouteStopTime/RouteStopTime.tsx +34 -0
  120. package/src/RouteStopTime/index.tsx +1 -0
  121. package/src/RvfMobilityMap/RvfMobilityMap.tsx +245 -0
  122. package/src/RvfMobilityMap/index.css +13 -0
  123. package/src/RvfMobilityMap/index.tsx +1 -0
  124. package/src/ScaleLine/ScaleLine.tsx +51 -0
  125. package/src/ScaleLine/index.css +6 -0
  126. package/src/ScaleLine/index.tsx +1 -0
  127. package/src/ScrollableHandler/ScrollableHandler.tsx +65 -0
  128. package/src/ScrollableHandler/index.tsx +1 -0
  129. package/src/Search/Search.tsx +18 -0
  130. package/src/Search/index.tsx +1 -0
  131. package/src/SingleClickListener/SingleClickListener.tsx +103 -0
  132. package/src/SingleClickListener/index.tsx +1 -0
  133. package/src/Station/Station.tsx +68 -0
  134. package/src/Station/index.tsx +1 -0
  135. package/src/StationHeader/StationHeader.tsx +32 -0
  136. package/src/StationHeader/index.tsx +1 -0
  137. package/src/StationName/StationName.tsx +21 -0
  138. package/src/StationName/index.tsx +1 -0
  139. package/src/StationServices/StationServices.tsx +80 -0
  140. package/src/StationServices/index.tsx +1 -0
  141. package/src/StationsLayer/StationsLayer.tsx +41 -0
  142. package/src/StationsLayer/index.tsx +1 -0
  143. package/src/StopsSearch/StopsSearch.tsx +254 -0
  144. package/src/StopsSearch/index.tsx +1 -0
  145. package/src/icons/Airport/Airport.tsx +17 -0
  146. package/src/icons/Airport/airport-14-svgrepo-com.svg +41 -0
  147. package/src/icons/Airport/index.tsx +1 -0
  148. package/src/icons/BarAndRestaurants/BarAndRestaurants.tsx +17 -0
  149. package/src/icons/BarAndRestaurants/food-restaurant-svgrepo-com.svg +12 -0
  150. package/src/icons/BarAndRestaurants/index.tsx +1 -0
  151. package/src/icons/Bathroom/Bathroom.tsx +59 -0
  152. package/src/icons/Bathroom/bathroom-restroom-svgrepo-com.svg +38 -0
  153. package/src/icons/Bathroom/index.tsx +1 -0
  154. package/src/icons/BikeStorage/BikeStorage.tsx +17 -0
  155. package/src/icons/BikeStorage/index.tsx +1 -0
  156. package/src/icons/BikeStorage/parking-bicycle-14-svgrepo-com.svg +41 -0
  157. package/src/icons/Elevator/Elevator.tsx +16 -0
  158. package/src/icons/Elevator/elevator-svgrepo-com.svg +2 -0
  159. package/src/icons/Elevator/index.tsx +1 -0
  160. package/src/icons/Police/Police.tsx +20 -0
  161. package/src/icons/Police/index.tsx +1 -0
  162. package/src/icons/Police/polizia.png +0 -0
  163. package/src/icons/README.md +52 -0
  164. package/src/icons/WaitingAreas/WaitingAreas.tsx +16 -0
  165. package/src/icons/WaitingAreas/highway-rest-area-svgrepo-com.svg +5 -0
  166. package/src/icons/WaitingAreas/index.tsx +1 -0
  167. package/src/icons/WaitingAreas/wheelchair-svgrepo-com.svg +2 -0
  168. package/src/icons/WheelChair/WheelChair.tsx +16 -0
  169. package/src/icons/WheelChair/disabili.png +0 -0
  170. package/src/icons/WheelChair/index.tsx +1 -0
  171. package/src/icons/WheelChair/wheelchair-svgrepo-com.svg +2 -0
  172. package/src/index.tsx +50 -0
  173. package/src/utils/MobilityEvent.ts +21 -0
  174. package/src/utils/addSourceAndLayers.ts +62 -0
  175. package/src/utils/centerOnStation.ts +17 -0
  176. package/src/utils/centerOnVehicle.ts +50 -0
  177. package/src/utils/getBgColor.ts +3 -0
  178. package/src/utils/getDelayColor.test.ts +20 -0
  179. package/src/utils/getDelayColor.ts +23 -0
  180. package/src/utils/getDelayColorForVehicle.test.ts +28 -0
  181. package/src/utils/getDelayColorForVehicle.ts +25 -0
  182. package/src/utils/getDelayFontForVehicle.test.ts +7 -0
  183. package/src/utils/getDelayFontForVehicle.tsx +8 -0
  184. package/src/utils/getDelayString.test.ts +22 -0
  185. package/src/utils/getDelayString.ts +28 -0
  186. package/src/utils/getDelayTextForVehicle.test.ts +28 -0
  187. package/src/utils/getDelayTextForVehicle.ts +21 -0
  188. package/src/utils/getFullTrajectoryAndFit.ts +40 -0
  189. package/src/utils/getHoursAndMinutes.test.ts +14 -0
  190. package/src/utils/getHoursAndMinutes.ts +22 -0
  191. package/src/utils/getMainColorForVehicle.test.ts +27 -0
  192. package/src/utils/getMainColorForVehicle.ts +46 -0
  193. package/src/utils/getStopStatus.test.ts +104 -0
  194. package/src/utils/getStopStatus.ts +171 -0
  195. package/src/utils/getTextFontForVehicle.test.ts +7 -0
  196. package/src/utils/getTextFontForVehicle.tsx +9 -0
  197. package/src/utils/getTextForVehicle.test.ts +17 -0
  198. package/src/utils/getTextForVehicle.ts +19 -0
  199. package/src/utils/hooks/useDebug.tsx +11 -0
  200. package/src/utils/hooks/useDeparture.tsx +23 -0
  201. package/src/utils/hooks/useI18n.tsx +20 -0
  202. package/src/utils/hooks/useMapContext.tsx +74 -0
  203. package/src/utils/hooks/useParams.ts +5 -0
  204. package/src/utils/hooks/useRouteStop.tsx +33 -0
  205. package/src/utils/hooks/useStation.tsx +21 -0
  206. package/src/utils/hooks/useUpdatePermalink.tsx +33 -0
  207. package/src/utils/hooks/useZoom.tsx +32 -0
  208. package/src/utils/i18n.ts +16 -0
  209. package/src/utils/translations.ts +31 -0
  210. package/tailwind.config.mjs +56 -0
  211. package/testNotification.json +50653 -0
  212. package/tsconfig.json +12 -0
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import { forwardRef } from "react";
3
+
4
+ // eslint-disable-next-line react/display-name
5
+ const GeopsMobility = forwardRef((props: Record<string, unknown>, ref) => {
6
+ return <geops-mobility ref={ref} {...props}></geops-mobility>;
7
+ });
8
+
9
+ export default GeopsMobility;
@@ -0,0 +1,231 @@
1
+ import { Typography } from "@mui/material";
2
+ import { Suspense } from "react";
3
+
4
+ import useIsFullScreen from "../hooks/useIsFullScreen";
5
+ import GeopsAPIKeyLink from "./GeopsAPIKeyLink";
6
+ import GeopsMapsAPILink from "./GeopsMapsAPILink";
7
+ import GeopsMobility from "./GeopsMobility";
8
+ import GeopsRealtimeAPILink from "./GeopsRealtimeAPILink";
9
+ import GeopsStopsAPILink from "./GeopsStopsAPILink";
10
+ import Link from "./Link";
11
+ import WebComponentDoc, { AttrConfig } from "./WebComponentDoc";
12
+
13
+ const attrsConfig: Record<string, AttrConfig> = {
14
+ apikey: {
15
+ description: (
16
+ <Typography>
17
+ Your <GeopsAPIKeyLink />.
18
+ </Typography>
19
+ ),
20
+ type: "textfield",
21
+ },
22
+ baselayer: {
23
+ defaultValue: "travic_v2",
24
+ description: (
25
+ <Typography>
26
+ The style&apos;s name from the <GeopsMapsAPILink />
27
+ (base_dark_v2, base_bright_v2, ...).
28
+ </Typography>
29
+ ),
30
+ type: "select",
31
+ },
32
+ center: {
33
+ defaultValue: "831634,5933959",
34
+ description: (
35
+ <Typography>The center of the map in EPSG:3857 coordinates.</Typography>
36
+ ),
37
+ type: "textfield",
38
+ },
39
+ geolocation: {
40
+ defaultValue: "true",
41
+ description: (
42
+ <Typography>
43
+ Display the geolocation button or not (true or false).
44
+ </Typography>
45
+ ),
46
+ type: "checkbox",
47
+ },
48
+ mapsurl: {
49
+ defaultValue: "https://maps.geops.io",
50
+ description: (
51
+ <Typography>
52
+ The <GeopsMapsAPILink /> url to use.
53
+ </Typography>
54
+ ),
55
+ type: "textfield",
56
+ },
57
+ maxzoom: {
58
+ description: <Typography>Define the max zoom level of the map.</Typography>,
59
+ props: {
60
+ slotProps: {
61
+ input: {
62
+ max: 22,
63
+ min: 0,
64
+ step: 1,
65
+ },
66
+ },
67
+ type: "number",
68
+ },
69
+ type: "textfield",
70
+ },
71
+ minzoom: {
72
+ description: <Typography>Define the min zoom level of the map.</Typography>,
73
+ props: {
74
+ slotProps: {
75
+ input: {
76
+ max: 22,
77
+ min: 0,
78
+ step: 1,
79
+ },
80
+ },
81
+ type: "number",
82
+ },
83
+ type: "textfield",
84
+ },
85
+ mots: {
86
+ description: (
87
+ <Typography>
88
+ Commas separated list of mots to display on the Realtime layer (rail,
89
+ bus, coach, foot, tram, subway, gondola, funicular, ferry, car).
90
+ </Typography>
91
+ ),
92
+ type: "textfield",
93
+ },
94
+ notification: {
95
+ defaultValue: "true",
96
+ description: (
97
+ <Typography>
98
+ Display the notification layer or not (true or false). This layer will
99
+ display informations about disruptions on the network. Data comes from
100
+ our{" "}
101
+ <Link href="https://geops.com/en/solution/disruption-information">
102
+ geOps MOCO tool
103
+ </Link>
104
+ . It works it combination with `notificationurl`.
105
+ </Typography>
106
+ ),
107
+ type: "checkbox",
108
+ },
109
+ notificationat: {
110
+ description: (
111
+ <Typography>
112
+ An ISO date string used to display active notification at this date in
113
+ the notification layer. If not defined the current date will be used.
114
+ </Typography>
115
+ ),
116
+ type: "textfield",
117
+ },
118
+ notificationbeforelayerid: {
119
+ description: (
120
+ <Typography>
121
+ The style layer&apos;s id before which the notification layer will be
122
+ added. By default the layer will be added on top.
123
+ </Typography>
124
+ ),
125
+ type: "textfield",
126
+ },
127
+ notificationurl: {
128
+ description: (
129
+ <Typography>
130
+ The{" "}
131
+ <Link href="https://geops.com/en/solution/disruption-information">
132
+ geOps MOCO API
133
+ </Link>{" "}
134
+ url to get the notifications from.
135
+ </Typography>
136
+ ),
137
+ type: "textfield",
138
+ },
139
+ // x,y,z are not applies on refresh
140
+ // permalink: {
141
+ // defaultValue: "false",
142
+ // description: (
143
+ // <Typography>
144
+ // Add automatically an `x`,`y` an `z` URL parameters to the URL to allow
145
+ // to share the current mapview. Default to false.
146
+ // </Typography>
147
+ // ),
148
+ // type: "checkbox",
149
+ // },
150
+ realtime: {
151
+ defaultValue: "true",
152
+ description: (
153
+ <Typography>
154
+ Display the realtime layer or not (true or false). This layer display
155
+ realtime vehicles on the map using the <GeopsRealtimeAPILink />.
156
+ </Typography>
157
+ ),
158
+ type: "checkbox",
159
+ },
160
+ realtimeurl: {
161
+ defaultValue: "wss://api.geops.io/tracker-ws/v1/ws",
162
+ description: (
163
+ <Typography>
164
+ The <GeopsRealtimeAPILink /> url to use.
165
+ </Typography>
166
+ ),
167
+ type: "textfield",
168
+ },
169
+ search: {
170
+ defaultValue: "true",
171
+ description: (
172
+ <Typography>
173
+ Display the search stops input or not (true or false).
174
+ </Typography>
175
+ ),
176
+ type: "checkbox",
177
+ },
178
+ stopsurl: {
179
+ defaultValue: "https://api.geops.io/stops/v1/",
180
+ description: (
181
+ <Typography>
182
+ The <GeopsStopsAPILink /> url to use.
183
+ </Typography>
184
+ ),
185
+ type: "textfield",
186
+ },
187
+ tenant: {
188
+ description: (
189
+ <Typography>
190
+ The tenant name to use to filter the Realtime vehicles available.
191
+ </Typography>
192
+ ),
193
+ type: "textfield",
194
+ },
195
+ zoom: {
196
+ defaultValue: "13",
197
+ description: <Typography>The initial zoom level of the map.</Typography>,
198
+ props: {
199
+ slotProps: {
200
+ input: {
201
+ max: 22,
202
+ min: 0,
203
+ step: 1,
204
+ },
205
+ },
206
+ type: "number",
207
+ },
208
+ type: "textfield",
209
+ },
210
+ };
211
+ function GeopsMobilityDoc() {
212
+ const isFullScreen = useIsFullScreen();
213
+
214
+ return (
215
+ <Suspense>
216
+ <WebComponentDoc
217
+ attrsConfig={attrsConfig}
218
+ // @ts-expect-error - must find the correct type
219
+ Comp={GeopsMobility}
220
+ compProps={{
221
+ class: isFullScreen
222
+ ? "fixed inset-0 w-screen h-sccreen z-[9000] bg-white"
223
+ : "block h-96 max-w-full resize overflow-auto bg-white",
224
+ }}
225
+ tagName="geops-mobility"
226
+ />
227
+ </Suspense>
228
+ );
229
+ }
230
+
231
+ export default GeopsMobilityDoc;
@@ -0,0 +1,10 @@
1
+ import { forwardRef } from "react";
2
+
3
+ // eslint-disable-next-line react/display-name
4
+ const GeopsMobilitySearch = forwardRef(
5
+ (props: Record<string, unknown>, ref) => {
6
+ return <geops-mobility-search ref={ref} {...props}></geops-mobility-search>;
7
+ },
8
+ );
9
+
10
+ export default GeopsMobilitySearch;
@@ -0,0 +1,129 @@
1
+ import { Typography } from "@mui/material";
2
+ import { Suspense } from "react";
3
+
4
+ import GeopsAPIKeyLink from "./GeopsAPIKeyLink";
5
+ import GeopsMobilitySearch from "./GeopsMobilitySearch";
6
+ import GeopsStopsAPILink from "./GeopsStopsAPILink";
7
+ import WebComponentDoc, { AttrConfig } from "./WebComponentDoc";
8
+
9
+ const attrsConfig: Record<string, AttrConfig> = {
10
+ apikey: {
11
+ description: (
12
+ <Typography>
13
+ Your <GeopsAPIKeyLink />.
14
+ </Typography>
15
+ ),
16
+ type: "textfield",
17
+ },
18
+ bbox: {
19
+ description: (
20
+ <Typography>
21
+ The extent where to search the stops (minx,miny,maxx,maxy).
22
+ </Typography>
23
+ ),
24
+ type: "textfield",
25
+ },
26
+ countrycode: {
27
+ description: (
28
+ <Typography>
29
+ The country code to filter the results (IT, DE, CH ...)
30
+ </Typography>
31
+ ),
32
+ type: "textfield",
33
+ },
34
+ event: {
35
+ defaultValue: "mwc:stopssearchselect",
36
+ description: (
37
+ <Typography>
38
+ The event&pos;s name to listen to when a stop is selected.
39
+ </Typography>
40
+ ),
41
+ type: "textfield",
42
+ },
43
+ field: {
44
+ description: (
45
+ <Typography>
46
+ Which field to look up, default all of them, Possible values:id, name,
47
+ coords.
48
+ </Typography>
49
+ ),
50
+ type: "textfield",
51
+ },
52
+ limit: {
53
+ defaultValue: "5",
54
+ description: <Typography>The number of suggestions to show.</Typography>,
55
+ props: {
56
+ slotProps: {
57
+ input: {
58
+ max: 100,
59
+ min: 0,
60
+ step: 1,
61
+ },
62
+ },
63
+ type: "number",
64
+ },
65
+ type: "textfield",
66
+ },
67
+ mots: {
68
+ description: (
69
+ <Typography>
70
+ Commas separated list of mots used to filter the results (rail, bus,
71
+ coach, foot, tram, subway, gondola, funicular, ferry, car).
72
+ </Typography>
73
+ ),
74
+ type: "textfield",
75
+ },
76
+ params: {
77
+ description: (
78
+ <Typography>
79
+ JSON string with additional parameters to pass to the request to the
80
+ API. Ex: {"{ 'key': 'value' }"}
81
+ </Typography>
82
+ ),
83
+ type: "textfield",
84
+ },
85
+ prefagencies: {
86
+ description: (
87
+ <Typography>
88
+ Comma seperated list, order chooses which agency will be preferred as
89
+ ident_source (for id and code fields). Possible values: sbb, db.
90
+ </Typography>
91
+ ),
92
+ type: "textfield",
93
+ },
94
+ reflocation: {
95
+ description: (
96
+ <Typography>
97
+ Coordinates in WGS84 (in lat,lon order) used to rank stops close to this
98
+ position higher
99
+ </Typography>
100
+ ),
101
+ type: "textfield",
102
+ },
103
+ url: {
104
+ defaultValue: "https://api.geops.io/stops/v1/",
105
+ description: (
106
+ <Typography>
107
+ The <GeopsStopsAPILink /> url to use.
108
+ </Typography>
109
+ ),
110
+ type: "textfield",
111
+ },
112
+ };
113
+
114
+ function GeopsMobilitySearchDoc() {
115
+ return (
116
+ <Suspense>
117
+ <WebComponentDoc
118
+ attrsConfig={attrsConfig}
119
+ // @ts-expect-error - must find the correct type
120
+ Comp={GeopsMobilitySearch}
121
+ compProps={{ class: "block w-full border" }}
122
+ events={["mwc:stopssearchselect"]}
123
+ tagName="geops-mobility-search"
124
+ />
125
+ </Suspense>
126
+ );
127
+ }
128
+
129
+ export default GeopsMobilitySearchDoc;
@@ -0,0 +1,10 @@
1
+ import Link from "./Link";
2
+
3
+ function GeopsRealtimeAPILink() {
4
+ return (
5
+ <Link href="https://developer.geops.io/apis/realtime">
6
+ geOps Realtime API
7
+ </Link>
8
+ );
9
+ }
10
+ export default GeopsRealtimeAPILink;
@@ -0,0 +1,8 @@
1
+ import Link from "./Link";
2
+
3
+ function GeopsStopsAPILink() {
4
+ return (
5
+ <Link href="https://developer.geops.io/apis/stops">geOps Stops API</Link>
6
+ );
7
+ }
8
+ export default GeopsStopsAPILink;
@@ -0,0 +1,9 @@
1
+ function Link({ children, ...props }: React.JSX.IntrinsicElements["a"]) {
2
+ return (
3
+ <a rel="noreferrer" target="_blank" {...props}>
4
+ <b>{children}</b>
5
+ </a>
6
+ );
7
+ }
8
+
9
+ export default Link;
@@ -0,0 +1,296 @@
1
+ "use client";
2
+ import {
3
+ Button,
4
+ Checkbox,
5
+ MenuItem,
6
+ Select,
7
+ TextField,
8
+ TextFieldProps,
9
+ Typography,
10
+ } from "@mui/material";
11
+ import { usePathname, useRouter, useSearchParams } from "next/navigation";
12
+ import {
13
+ ReactElement,
14
+ ReactNode,
15
+ useCallback,
16
+ useEffect,
17
+ useMemo,
18
+ useRef,
19
+ } from "react";
20
+ import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
21
+
22
+ import useAttrFromUrlParams from "../hooks/useAttrFromUrlParams";
23
+ import usePublicKey from "../hooks/usePublicKey";
24
+
25
+ export interface AttrConfig {
26
+ defaultValue?: string;
27
+ description: ReactNode;
28
+ props?: TextFieldProps;
29
+ type: "checkbox" | "date" | "select" | "textfield";
30
+ }
31
+
32
+ function WebComponentDoc({
33
+ attrsConfig,
34
+ Comp,
35
+ compProps,
36
+ events,
37
+ isFullScreen,
38
+ tagName,
39
+ }: {
40
+ attrsConfig: Record<string, AttrConfig>;
41
+ Comp: (props: Record<string, string>) => ReactElement;
42
+ compProps: Record<string, string>;
43
+ events?: string[];
44
+ isFullScreen?: boolean;
45
+ tagName: string;
46
+ }) {
47
+ const wcAttributes = Object.keys(attrsConfig);
48
+ const ref = useRef<HTMLElement>(null);
49
+ const router = useRouter();
50
+ const pathname = usePathname();
51
+ const apiKey = usePublicKey();
52
+ const attributes = useAttrFromUrlParams(wcAttributes);
53
+ const searchParams = useSearchParams();
54
+
55
+ // Get a new searchParams string by merging the current
56
+ // searchParams with a provided key/value pair
57
+ const createQueryString = useCallback(
58
+ (name: string, value?: string) => {
59
+ const params = new URLSearchParams(searchParams.toString());
60
+ if (value === undefined || value === "") {
61
+ params.delete(name);
62
+ } else {
63
+ params.set(name, value);
64
+ }
65
+
66
+ return params.toString();
67
+ },
68
+ [searchParams],
69
+ );
70
+
71
+ const code = useMemo(() => {
72
+ let str = `<script\n\ttype="module"\n\tsrc="https://www.unpkg.com/@geops/mobility-web-component">
73
+ </script>
74
+ <${tagName}`;
75
+
76
+ str = Object.keys({ apikey: "", ...attributes }).reduce((acc, key) => {
77
+ if (key === "apikey" && !attributes[key]) {
78
+ return `${acc}\n\tapikey="YOUR_GEOPS_API_KEY"`;
79
+ }
80
+ return `${acc}\n\t${key}="${attributes[key]}"`;
81
+ }, str);
82
+
83
+ str += `>\n</${tagName}>`;
84
+
85
+ return str;
86
+ }, [attributes, tagName]);
87
+
88
+ const onChange = useCallback(
89
+ (key: string, value: string) => {
90
+ const val = value === attrsConfig[key]?.defaultValue ? undefined : value;
91
+ router.replace(pathname + "?" + createQueryString(key, val), {
92
+ scroll: false,
93
+ });
94
+ },
95
+ [attrsConfig, createQueryString, pathname, router],
96
+ );
97
+
98
+ useEffect(() => {
99
+ const cb = (event: CustomEvent<{ data: object; type: string }>) => {
100
+ const eventLog = document.getElementById("textarea");
101
+ // @ts-expect-error - strange error
102
+ const data = event.data;
103
+ if (!eventLog) {
104
+ return;
105
+ }
106
+ if (!data) {
107
+ eventLog.innerText = "";
108
+ } else {
109
+ eventLog.innerText =
110
+ "Event " +
111
+ event.type +
112
+ " received :\n " +
113
+ JSON.stringify(data, undefined, " ");
114
+ // window.top.postMessage(data, "*");
115
+ }
116
+ };
117
+ if (ref.current) {
118
+ // Listen to element event
119
+ events?.forEach((event) => {
120
+ // @ts-expect-error - strange error
121
+ ref.current?.addEventListener(event, cb);
122
+ });
123
+ }
124
+ return () => {
125
+ events?.forEach((event) => {
126
+ // @ts-expect-error - strange error
127
+ ref.current?.removeEventListener(event, cb);
128
+ });
129
+ };
130
+ }, [events]);
131
+
132
+ const webComponent = useMemo(() => {
133
+ return (
134
+ <Comp
135
+ // @ts-expect-error - strange error
136
+ apikey={apiKey}
137
+ {...attributes}
138
+ // @ts-expect-error - strange error
139
+ ref={(node: HTMLElement) => {
140
+ // @ts-expect-error - strange error
141
+ ref.current = node;
142
+ }}
143
+ {...compProps}
144
+ />
145
+ );
146
+ }, [Comp, apiKey, attributes, compProps]);
147
+
148
+ if (isFullScreen) {
149
+ return webComponent;
150
+ }
151
+
152
+ return (
153
+ <div className="mb-48 scroll-mt-20">
154
+ <Typography variant="h1">{`<${tagName} />`}</Typography>
155
+ <br />
156
+ <Typography>
157
+ This is a demo of the &lt;{tagName} /&gt; Web Component.
158
+ </Typography>
159
+ <br />
160
+ {webComponent}
161
+ <br />
162
+ {events?.length && (
163
+ <>
164
+ <Typography className="my-8 overflow-auto" variant="h3">
165
+ Event received
166
+ </Typography>
167
+ <pre
168
+ className="h-40 w-full overflow-auto border p-2"
169
+ id="textarea"
170
+ ></pre>
171
+ <br />
172
+ </>
173
+ )}
174
+ <Typography className="my-8" variant="h2">
175
+ HTML code
176
+ </Typography>
177
+ <br />
178
+ <SyntaxHighlighter className="!m-0" language="xml">
179
+ {code}
180
+ </SyntaxHighlighter>
181
+ <br />
182
+ <Typography className="flex gap-4" variant="h2">
183
+ Attributes
184
+ <Button
185
+ onClick={() => {
186
+ router.push(pathname, {
187
+ scroll: false,
188
+ });
189
+ }}
190
+ >
191
+ Reset
192
+ </Button>
193
+ </Typography>
194
+ <br />
195
+
196
+ <table className="w-full">
197
+ <thead>
198
+ <tr>
199
+ <th className="w-[15%] border px-4 py-2">Name</th>
200
+ <th className="w-2/5 border px-4 py-2">Value</th>
201
+ <th className="w-[45%] border px-4 py-2">Description</th>
202
+ </tr>
203
+ </thead>
204
+ <tbody>
205
+ {wcAttributes
206
+ .sort((a, b) => {
207
+ return a < b ? -1 : 1;
208
+ })
209
+ .filter((key) => {
210
+ return attrsConfig[key]?.description;
211
+ })
212
+ .map((key) => {
213
+ const {
214
+ defaultValue,
215
+ description,
216
+ props = {},
217
+ type,
218
+ } = attrsConfig[key] || {};
219
+ return (
220
+ <tr key={key}>
221
+ <td className="border px-4 py-2">{key}</td>
222
+ <td className="border px-4 py-2">
223
+ {type === "textfield" && (
224
+ <div>
225
+ <TextField
226
+ defaultValue={attributes[key]}
227
+ fullWidth
228
+ id={key}
229
+ placeholder={defaultValue}
230
+ variant="standard"
231
+ {...props}
232
+ />
233
+ <div className="mt-2">
234
+ <Button
235
+ fullWidth
236
+ onClick={() => {
237
+ onChange(
238
+ key,
239
+ (
240
+ document.getElementById(
241
+ key,
242
+ ) as HTMLInputElement
243
+ )?.value,
244
+ );
245
+ }}
246
+ >
247
+ Apply
248
+ </Button>
249
+ </div>
250
+ </div>
251
+ )}
252
+
253
+ {type === "checkbox" && (
254
+ <Checkbox
255
+ defaultChecked={
256
+ (searchParams.get(key) || defaultValue) === "true"
257
+ }
258
+ onChange={(evt) => {
259
+ onChange(key, evt.target.checked ? "true" : "false");
260
+ }}
261
+ />
262
+ )}
263
+
264
+ {type === "select" && (
265
+ <Select
266
+ defaultValue={searchParams.get(key) || defaultValue}
267
+ fullWidth
268
+ onChange={(evt) => {
269
+ onChange(key, evt.target.value);
270
+ }}
271
+ variant="standard"
272
+ >
273
+ <MenuItem value="travic_v2">Travic v2</MenuItem>
274
+ <MenuItem value="base_dark_v2">Dark v2</MenuItem>
275
+ </Select>
276
+ )}
277
+ </td>
278
+ <td className="border p-4">
279
+ {description}{" "}
280
+ {defaultValue && (
281
+ <>
282
+ <br />
283
+ <i>Default to &quot;{defaultValue}&quot;</i>
284
+ </>
285
+ )}
286
+ </td>
287
+ </tr>
288
+ );
289
+ })}
290
+ </tbody>
291
+ </table>
292
+ </div>
293
+ );
294
+ }
295
+
296
+ export default WebComponentDoc;
Binary file