@unabridged/midwest 0.24.0 → 0.24.4

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 (41) hide show
  1. package/app/assets/javascript/midwest/index.ts +10 -0
  2. package/app/assets/javascript/midwest/map_providers.ts +61 -0
  3. package/app/assets/javascript/midwest/viewport_observer.ts +49 -0
  4. package/app/assets/javascript/midwest.js +1056 -70
  5. package/app/assets/javascript/midwest.js.map +1 -1
  6. package/app/assets/stylesheets/midwest.css +1 -1
  7. package/app/assets/stylesheets/midwest.tailwind.css +7 -1
  8. package/dist/css/midwest.css +1 -1
  9. package/dist/javascript/collection/app/assets/javascript/midwest/index.js +10 -0
  10. package/dist/javascript/collection/app/assets/javascript/midwest/index.js.map +1 -1
  11. package/dist/javascript/collection/app/assets/javascript/midwest/map_providers.js +56 -0
  12. package/dist/javascript/collection/app/assets/javascript/midwest/map_providers.js.map +1 -0
  13. package/dist/javascript/collection/app/assets/javascript/midwest/viewport_observer.js +22 -0
  14. package/dist/javascript/collection/app/assets/javascript/midwest/viewport_observer.js.map +1 -0
  15. package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js +4 -7
  16. package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js.map +1 -1
  17. package/dist/javascript/collection/app/components/midwest/dropdown_component/dropdown_component_controller.js +0 -6
  18. package/dist/javascript/collection/app/components/midwest/dropdown_component/dropdown_component_controller.js.map +1 -1
  19. package/dist/javascript/collection/app/components/midwest/form/address_component/address_component_controller.js +441 -0
  20. package/dist/javascript/collection/app/components/midwest/form/address_component/address_component_controller.js.map +1 -0
  21. package/dist/javascript/collection/app/components/midwest/form/live_summary_component/live_summary_component_controller.js +55 -1
  22. package/dist/javascript/collection/app/components/midwest/form/live_summary_component/live_summary_component_controller.js.map +1 -1
  23. package/dist/javascript/collection/app/components/midwest/intersection_observer_component/intersection_observer_component_controller.js +20 -25
  24. package/dist/javascript/collection/app/components/midwest/intersection_observer_component/intersection_observer_component_controller.js.map +1 -1
  25. package/dist/javascript/collection/app/components/midwest/map_component/map_component_controller.js +297 -0
  26. package/dist/javascript/collection/app/components/midwest/map_component/map_component_controller.js.map +1 -0
  27. package/dist/javascript/collection/app/components/midwest/motion_component/motion_component_controller.js +32 -0
  28. package/dist/javascript/collection/app/components/midwest/motion_component/motion_component_controller.js.map +1 -0
  29. package/dist/javascript/collection/app/components/midwest/notification_component/notification_component_controller.js +4 -12
  30. package/dist/javascript/collection/app/components/midwest/notification_component/notification_component_controller.js.map +1 -1
  31. package/dist/javascript/collection/app/components/midwest/onboarding_component/onboarding_component_controller.js +34 -5
  32. package/dist/javascript/collection/app/components/midwest/onboarding_component/onboarding_component_controller.js.map +1 -1
  33. package/dist/javascript/collection/app/components/midwest/page_transition_component/page_transition_component_controller.js +38 -0
  34. package/dist/javascript/collection/app/components/midwest/page_transition_component/page_transition_component_controller.js.map +1 -0
  35. package/dist/javascript/collection/app/components/midwest/popover_component/popover_component_controller.js +67 -0
  36. package/dist/javascript/collection/app/components/midwest/popover_component/popover_component_controller.js.map +1 -0
  37. package/dist/javascript/collection/app/components/midwest/table_component/load_more_controller.js +10 -14
  38. package/dist/javascript/collection/app/components/midwest/table_component/load_more_controller.js.map +1 -1
  39. package/dist/javascript/midwest.js +1056 -70
  40. package/dist/javascript/midwest.js.map +1 -1
  41. package/package.json +1 -1
@@ -0,0 +1,441 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ import { loadMapKitScript, loadGoogleMapsScript, loadLeafletScript } from '../../../../assets/javascript/midwest/map_providers.js';
3
+
4
+ const DEBOUNCE_MS = 300;
5
+ const GOOGLE_PREVIEW_STYLES = [
6
+ { elementType: "geometry", stylers: [{ color: "#f5f5f5" }] },
7
+ { elementType: "labels.icon", stylers: [{ visibility: "off" }] },
8
+ { elementType: "labels.text.fill", stylers: [{ color: "#616161" }] },
9
+ { elementType: "labels.text.stroke", stylers: [{ color: "#f5f5f5" }] },
10
+ { featureType: "road", elementType: "geometry", stylers: [{ color: "#ffffff" }] },
11
+ { featureType: "road.highway", elementType: "geometry", stylers: [{ color: "#dadada" }] },
12
+ { featureType: "water", elementType: "geometry", stylers: [{ color: "#c9c9c9" }] },
13
+ { featureType: "poi", elementType: "geometry", stylers: [{ color: "#eeeeee" }] }
14
+ ];
15
+ class Address extends Controller {
16
+ static targets = [
17
+ "input",
18
+ "dropdown",
19
+ "suggestions",
20
+ "latInput",
21
+ "lngInput",
22
+ "placeIdInput",
23
+ "mapContainer"
24
+ ];
25
+ static values = {
26
+ provider: { type: String, default: "" },
27
+ mapProvider: { type: String, default: "" },
28
+ apiKey: { type: String, default: "" },
29
+ token: { type: String, default: "" },
30
+ tokenUrl: { type: String, default: "" },
31
+ countryCodes: { type: Array, default: [] },
32
+ showMap: { type: Boolean, default: false },
33
+ nominatimUrl: { type: String, default: "" }
34
+ };
35
+ searchTimer;
36
+ highlightedIndex = -1;
37
+ mapInstance = null;
38
+ mapMarker = null;
39
+ mkSearch = null;
40
+ autocompleteService = null;
41
+ placesService = null;
42
+ // ── Named handlers ────────────────────────────────────────────────────────
43
+ onToggle = (e) => {
44
+ const opened = e.newState === "open";
45
+ if (this.hasInputTarget) {
46
+ this.inputTarget.setAttribute("aria-expanded", String(opened));
47
+ }
48
+ if (!opened) {
49
+ this.highlightedIndex = -1;
50
+ }
51
+ };
52
+ onFocusOut = (e) => {
53
+ if (!this.element.contains(e.relatedTarget)) {
54
+ this.closeDropdown();
55
+ }
56
+ };
57
+ // ── Lifecycle ─────────────────────────────────────────────────────────────
58
+ async connect() {
59
+ this.element.addEventListener("focusout", this.onFocusOut);
60
+ const provider = this.providerValue;
61
+ const mapProv = this.effectiveMapProvider();
62
+ if (!provider && !mapProv)
63
+ return;
64
+ try {
65
+ if (provider === "mapkit") {
66
+ await loadMapKitScript();
67
+ this.initMapKit();
68
+ } else if (provider === "google") {
69
+ await loadGoogleMapsScript(this.apiKeyValue);
70
+ this.initGoogle();
71
+ }
72
+ if (this.showMapValue && mapProv === "leaflet") {
73
+ await loadLeafletScript();
74
+ }
75
+ } catch (err) {
76
+ console.error("[midwest-address] Failed to initialise:", err);
77
+ }
78
+ }
79
+ disconnect() {
80
+ clearTimeout(this.searchTimer);
81
+ this.element.removeEventListener("focusout", this.onFocusOut);
82
+ if (this.mapInstance) {
83
+ const mapProv = this.effectiveMapProvider();
84
+ if (mapProv === "mapkit")
85
+ this.mapInstance.destroy();
86
+ if (mapProv === "leaflet")
87
+ this.mapInstance.remove();
88
+ }
89
+ this.mapInstance = null;
90
+ }
91
+ dropdownTargetConnected(el) {
92
+ el.addEventListener("toggle", this.onToggle);
93
+ }
94
+ dropdownTargetDisconnected(el) {
95
+ el.removeEventListener("toggle", this.onToggle);
96
+ }
97
+ // ── Public Stimulus actions ───────────────────────────────────────────────
98
+ search() {
99
+ this.clearGeocode();
100
+ const query = this.inputTarget.value.trim();
101
+ if (query.length < 2) {
102
+ this.closeDropdown();
103
+ return;
104
+ }
105
+ clearTimeout(this.searchTimer);
106
+ this.searchTimer = setTimeout(() => {
107
+ if (this.providerValue === "mapkit") {
108
+ this.searchMapKit(query);
109
+ } else if (this.providerValue === "google") {
110
+ this.searchGoogle(query);
111
+ } else if (this.providerValue === "nominatim") {
112
+ this.searchNominatim(query);
113
+ }
114
+ }, DEBOUNCE_MS);
115
+ }
116
+ navigate(event) {
117
+ const items = this.suggestionElements();
118
+ if (!items.length)
119
+ return;
120
+ switch (event.key) {
121
+ case "ArrowDown":
122
+ event.preventDefault();
123
+ this.highlightedIndex = Math.min(this.highlightedIndex + 1, items.length - 1);
124
+ this.applyHighlight(items);
125
+ break;
126
+ case "ArrowUp":
127
+ event.preventDefault();
128
+ this.highlightedIndex = Math.max(this.highlightedIndex - 1, -1);
129
+ this.applyHighlight(items);
130
+ break;
131
+ case "Enter":
132
+ event.preventDefault();
133
+ if (this.highlightedIndex >= 0)
134
+ items[this.highlightedIndex].dispatchEvent(new MouseEvent("mousedown"));
135
+ break;
136
+ case "Escape":
137
+ this.closeDropdown();
138
+ break;
139
+ }
140
+ }
141
+ // ── Provider init ─────────────────────────────────────────────────────────
142
+ initMapKit() {
143
+ const mk = window.mapkit;
144
+ const { tokenValue: token, tokenUrlValue: tokenUrl } = this;
145
+ mk.init({
146
+ authorizationCallback: (done) => {
147
+ if (token) {
148
+ done(token);
149
+ } else if (tokenUrl) {
150
+ fetch(tokenUrl).then((r) => r.text()).then(done).catch((err) => console.error("[midwest-address] Token fetch failed:", err));
151
+ }
152
+ },
153
+ language: document.documentElement.lang || "en"
154
+ });
155
+ this.mkSearch = new mk.Search({ getsUserLocation: false });
156
+ }
157
+ initGoogle() {
158
+ const g = window.google;
159
+ this.autocompleteService = new g.maps.places.AutocompleteService();
160
+ this.placesService = new g.maps.places.PlacesService(document.createElement("div"));
161
+ }
162
+ // ── Search ────────────────────────────────────────────────────────────────
163
+ searchMapKit(query) {
164
+ if (!this.mkSearch)
165
+ return;
166
+ this.mkSearch.autocomplete(query, (err, data) => {
167
+ if (err || !data?.results?.length) {
168
+ this.closeDropdown();
169
+ return;
170
+ }
171
+ const results = data.results.map((r) => ({
172
+ id: r.completionURL ?? r.displayLines?.join(", ") ?? "",
173
+ label: r.displayLines?.[0] ?? "",
174
+ secondary: r.displayLines?.[1] ?? "",
175
+ payload: r
176
+ }));
177
+ this.renderSuggestions(results);
178
+ });
179
+ }
180
+ searchGoogle(query) {
181
+ if (!this.autocompleteService)
182
+ return;
183
+ const request = { input: query };
184
+ if (this.countryCodesValue.length) {
185
+ request.componentRestrictions = { country: this.countryCodesValue };
186
+ }
187
+ this.autocompleteService.getPlacePredictions(
188
+ request,
189
+ (predictions, status) => {
190
+ const g = window.google;
191
+ if (status !== g.maps.places.PlacesServiceStatus.OK || !predictions?.length) {
192
+ this.closeDropdown();
193
+ return;
194
+ }
195
+ const results = predictions.map((p) => ({
196
+ id: p.place_id,
197
+ label: p.structured_formatting?.main_text ?? p.description,
198
+ secondary: p.structured_formatting?.secondary_text ?? "",
199
+ payload: p
200
+ }));
201
+ this.renderSuggestions(results);
202
+ }
203
+ );
204
+ }
205
+ // ── Suggestions UI ────────────────────────────────────────────────────────
206
+ renderSuggestions(results) {
207
+ if (!this.hasSuggestionsTarget)
208
+ return;
209
+ const list = this.suggestionsTarget;
210
+ list.innerHTML = "";
211
+ results.forEach((r, i) => {
212
+ const li = document.createElement("li");
213
+ li.className = "midwest-address__suggestion";
214
+ li.setAttribute("role", "option");
215
+ li.setAttribute("id", `${this.element.id || "addr"}-s${i}`);
216
+ li.dataset.index = String(i);
217
+ const main = document.createElement("span");
218
+ main.className = "midwest-address__suggestion-main";
219
+ main.textContent = r.label;
220
+ li.appendChild(main);
221
+ if (r.secondary) {
222
+ const sec = document.createElement("span");
223
+ sec.className = "midwest-address__suggestion-secondary";
224
+ sec.textContent = r.secondary;
225
+ li.appendChild(sec);
226
+ }
227
+ li.addEventListener("mousedown", (e) => {
228
+ e.preventDefault();
229
+ this.pickSuggestion(r);
230
+ });
231
+ list.appendChild(li);
232
+ });
233
+ this.openDropdown();
234
+ this.highlightedIndex = -1;
235
+ }
236
+ openDropdown() {
237
+ if (!this.hasDropdownTarget)
238
+ return;
239
+ if (!this.dropdownTarget.matches(":popover-open"))
240
+ this.dropdownTarget.showPopover();
241
+ }
242
+ closeDropdown() {
243
+ if (this.hasDropdownTarget && this.dropdownTarget.matches(":popover-open")) {
244
+ this.dropdownTarget.hidePopover();
245
+ }
246
+ if (this.hasSuggestionsTarget)
247
+ this.suggestionsTarget.innerHTML = "";
248
+ this.highlightedIndex = -1;
249
+ }
250
+ suggestionElements() {
251
+ if (!this.hasSuggestionsTarget)
252
+ return [];
253
+ return Array.from(this.suggestionsTarget.querySelectorAll(".midwest-address__suggestion"));
254
+ }
255
+ applyHighlight(items) {
256
+ items.forEach((item, i) => {
257
+ const active = i === this.highlightedIndex;
258
+ item.classList.toggle("is-highlighted", active);
259
+ item.setAttribute("aria-selected", String(active));
260
+ if (active) {
261
+ this.inputTarget.setAttribute("aria-activedescendant", item.id);
262
+ item.scrollIntoView({ block: "nearest" });
263
+ }
264
+ });
265
+ if (this.highlightedIndex < 0) {
266
+ this.inputTarget.removeAttribute("aria-activedescendant");
267
+ }
268
+ }
269
+ // ── Pick a suggestion ─────────────────────────────────────────────────────
270
+ pickSuggestion(r) {
271
+ this.closeDropdown();
272
+ if (this.providerValue === "mapkit") {
273
+ this.pickMapKit(r);
274
+ } else if (this.providerValue === "google") {
275
+ this.pickGoogle(r);
276
+ } else if (this.providerValue === "nominatim") {
277
+ this.pickNominatim(r);
278
+ }
279
+ }
280
+ pickMapKit(r) {
281
+ if (!this.mkSearch)
282
+ return;
283
+ this.mkSearch.search(r.payload, (err, data) => {
284
+ if (err || !data?.places?.length)
285
+ return;
286
+ const place = data.places[0];
287
+ const coord = place.coordinate;
288
+ this.inputTarget.value = [r.label, r.secondary].filter(Boolean).join(", ");
289
+ this.fillGeocode(coord.latitude, coord.longitude, place.id ?? "");
290
+ this.updateMapPreview(coord.latitude, coord.longitude);
291
+ });
292
+ }
293
+ pickGoogle(r) {
294
+ if (!this.placesService || !r.id)
295
+ return;
296
+ const g = window.google;
297
+ this.placesService.getDetails(
298
+ { placeId: r.id, fields: ["geometry", "formatted_address", "place_id"] },
299
+ (place, status) => {
300
+ if (status !== g.maps.places.PlacesServiceStatus.OK || !place)
301
+ return;
302
+ const lat = place.geometry.location.lat();
303
+ const lng = place.geometry.location.lng();
304
+ this.inputTarget.value = place.formatted_address;
305
+ this.fillGeocode(lat, lng, place.place_id);
306
+ this.updateMapPreview(lat, lng);
307
+ }
308
+ );
309
+ }
310
+ // ── Geocode field management ──────────────────────────────────────────────
311
+ fillGeocode(lat, lng, placeId) {
312
+ if (this.hasLatInputTarget)
313
+ this.latInputTarget.value = String(lat);
314
+ if (this.hasLngInputTarget)
315
+ this.lngInputTarget.value = String(lng);
316
+ if (this.hasPlaceIdInputTarget)
317
+ this.placeIdInputTarget.value = placeId;
318
+ this.dispatch("geocode", { detail: { lat, lng, placeId } });
319
+ }
320
+ clearGeocode() {
321
+ if (this.hasLatInputTarget)
322
+ this.latInputTarget.value = "";
323
+ if (this.hasLngInputTarget)
324
+ this.lngInputTarget.value = "";
325
+ if (this.hasPlaceIdInputTarget)
326
+ this.placeIdInputTarget.value = "";
327
+ }
328
+ // ── Nominatim search (OpenStreetMap, no API key) ──────────────────────────
329
+ searchNominatim(query) {
330
+ const base = this.nominatimUrlValue || "https://nominatim.openstreetmap.org";
331
+ const url = `${base}/search?q=${encodeURIComponent(query)}&format=json&limit=5&addressdetails=1`;
332
+ fetch(url, { headers: { "Accept-Language": document.documentElement.lang || "en" } }).then((r) => r.json()).then((data) => {
333
+ if (!data?.length) {
334
+ this.closeDropdown();
335
+ return;
336
+ }
337
+ const results = data.map((r) => {
338
+ const parts = r.display_name.split(", ");
339
+ return {
340
+ id: String(r.place_id),
341
+ label: r.name || parts[0] || r.display_name,
342
+ secondary: parts.length > 1 ? parts.slice(1).join(", ") : "",
343
+ payload: r
344
+ };
345
+ });
346
+ this.renderSuggestions(results);
347
+ }).catch(() => this.closeDropdown());
348
+ }
349
+ pickNominatim(r) {
350
+ const place = r.payload;
351
+ const lat = parseFloat(place.lat);
352
+ const lng = parseFloat(place.lon);
353
+ this.inputTarget.value = place.display_name;
354
+ this.fillGeocode(lat, lng, `${place.osm_type}:${place.osm_id}`);
355
+ this.updateMapPreview(lat, lng);
356
+ }
357
+ // ── Map preview ───────────────────────────────────────────────────────────
358
+ // Returns the provider used for the map preview. `mapProviderValue` is set
359
+ // when the geocoder and map providers differ; falls back to `providerValue`
360
+ // so existing single-provider setups (mapkit/google) work without change.
361
+ effectiveMapProvider() {
362
+ return this.mapProviderValue || this.providerValue;
363
+ }
364
+ updateMapPreview(lat, lng) {
365
+ if (!this.hasMapContainerTarget || !this.showMapValue)
366
+ return;
367
+ this.mapContainerTarget.hidden = false;
368
+ const mapProv = this.effectiveMapProvider();
369
+ if (mapProv === "mapkit") {
370
+ this.updateMapKitPreview(lat, lng);
371
+ } else if (mapProv === "google") {
372
+ this.updateGooglePreview(lat, lng);
373
+ } else if (mapProv === "leaflet") {
374
+ this.updateLeafletPreview(lat, lng);
375
+ }
376
+ }
377
+ updateMapKitPreview(lat, lng) {
378
+ const mk = window.mapkit;
379
+ const coord = new mk.Coordinate(lat, lng);
380
+ if (!this.mapInstance) {
381
+ this.mapInstance = new mk.Map(this.mapContainerTarget, {
382
+ mapType: mk.Map.MapTypes.MutedStandard,
383
+ showsCompass: mk.FeatureVisibility.Hidden,
384
+ showsZoomControl: false,
385
+ showsMapTypeControl: false,
386
+ isScrollEnabled: false,
387
+ isZoomEnabled: false
388
+ });
389
+ }
390
+ this.mapInstance.setRegionAnimated(
391
+ new mk.CoordinateRegion(coord, new mk.CoordinateSpan(0.01, 0.01))
392
+ );
393
+ if (this.mapMarker)
394
+ this.mapInstance.removeAnnotation(this.mapMarker);
395
+ this.mapMarker = new mk.MarkerAnnotation(coord);
396
+ this.mapInstance.addAnnotation(this.mapMarker);
397
+ }
398
+ updateGooglePreview(lat, lng) {
399
+ const g = window.google;
400
+ const center = { lat, lng };
401
+ if (!this.mapInstance) {
402
+ this.mapInstance = new g.maps.Map(this.mapContainerTarget, {
403
+ center,
404
+ zoom: 15,
405
+ disableDefaultUI: true,
406
+ gestureHandling: "none",
407
+ styles: GOOGLE_PREVIEW_STYLES
408
+ });
409
+ } else {
410
+ this.mapInstance.setCenter(center);
411
+ this.mapInstance.setZoom(15);
412
+ }
413
+ if (this.mapMarker)
414
+ this.mapMarker.setMap(null);
415
+ this.mapMarker = new g.maps.Marker({ map: this.mapInstance, position: center });
416
+ }
417
+ updateLeafletPreview(lat, lng) {
418
+ const L = window.L;
419
+ if (!L)
420
+ return;
421
+ if (!this.mapInstance) {
422
+ this.mapInstance = L.map(this.mapContainerTarget, {
423
+ center: [lat, lng],
424
+ zoom: 15,
425
+ zoomControl: false,
426
+ attributionControl: false
427
+ });
428
+ L.tileLayer("https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png", {
429
+ maxZoom: 19
430
+ }).addTo(this.mapInstance);
431
+ } else {
432
+ this.mapInstance.setView([lat, lng], 15);
433
+ }
434
+ if (this.mapMarker)
435
+ this.mapMarker.remove();
436
+ this.mapMarker = L.marker([lat, lng]).addTo(this.mapInstance);
437
+ }
438
+ }
439
+
440
+ export { Address as default };
441
+ //# sourceMappingURL=address_component_controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address_component_controller.js","sources":["../../../../../../../../app/components/midwest/form/address_component/address_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\nimport { loadMapKitScript, loadGoogleMapsScript, loadLeafletScript } from '../../../../assets/javascript/midwest/map_providers'\n\n// Milliseconds to wait after the last keystroke before firing the search.\nconst DEBOUNCE_MS = 300\n\ninterface NominatimResult {\n place_id: number\n osm_type: string\n osm_id: number\n lat: string\n lon: string\n display_name: string\n name?: string\n address?: Record<string, string>\n}\n\n// Compact muted style for the Google Maps preview.\nconst GOOGLE_PREVIEW_STYLES = [\n { elementType: 'geometry', stylers: [{ color: '#f5f5f5' }] },\n { elementType: 'labels.icon', stylers: [{ visibility: 'off' }] },\n { elementType: 'labels.text.fill', stylers: [{ color: '#616161' }] },\n { elementType: 'labels.text.stroke', stylers: [{ color: '#f5f5f5' }] },\n { featureType: 'road', elementType: 'geometry', stylers: [{ color: '#ffffff' }] },\n { featureType: 'road.highway', elementType: 'geometry', stylers: [{ color: '#dadada' }] },\n { featureType: 'water', elementType: 'geometry', stylers: [{ color: '#c9c9c9' }] },\n { featureType: 'poi', elementType: 'geometry', stylers: [{ color: '#eeeeee' }] }\n]\n\ninterface Suggestion {\n id: string\n label: string\n secondary: string\n // Opaque payload carried through to the detail fetch\n payload: any\n}\n\nexport default class Address extends Controller<HTMLElement> {\n static targets = [\n 'input',\n 'dropdown',\n 'suggestions',\n 'latInput',\n 'lngInput',\n 'placeIdInput',\n 'mapContainer'\n ]\n\n static values = {\n provider: { type: String, default: '' },\n mapProvider: { type: String, default: '' },\n apiKey: { type: String, default: '' },\n token: { type: String, default: '' },\n tokenUrl: { type: String, default: '' },\n countryCodes: { type: Array, default: [] },\n showMap: { type: Boolean, default: false },\n nominatimUrl: { type: String, default: '' }\n }\n\n declare readonly inputTarget: HTMLInputElement\n declare readonly hasInputTarget: boolean\n declare readonly dropdownTarget: HTMLElement\n declare readonly hasDropdownTarget: boolean\n declare readonly suggestionsTarget: HTMLUListElement\n declare readonly hasSuggestionsTarget: boolean\n declare readonly latInputTarget: HTMLInputElement\n declare readonly hasLatInputTarget: boolean\n declare readonly lngInputTarget: HTMLInputElement\n declare readonly hasLngInputTarget: boolean\n declare readonly placeIdInputTarget: HTMLInputElement\n declare readonly hasPlaceIdInputTarget: boolean\n declare readonly mapContainerTarget: HTMLElement\n declare readonly hasMapContainerTarget: boolean\n\n declare providerValue: string\n declare mapProviderValue: string\n declare apiKeyValue: string\n declare tokenValue: string\n declare tokenUrlValue: string\n declare countryCodesValue: string[]\n declare showMapValue: boolean\n declare nominatimUrlValue: string\n\n private searchTimer: ReturnType<typeof setTimeout> | undefined\n private highlightedIndex = -1\n private mapInstance: any = null\n private mapMarker: any = null\n private mkSearch: any = null\n private autocompleteService: any = null\n private placesService: any = null\n\n // ── Named handlers ────────────────────────────────────────────────────────\n\n private onToggle = (e: Event) => {\n const opened = (e as ToggleEvent).newState === 'open'\n if (this.hasInputTarget) {\n this.inputTarget.setAttribute('aria-expanded', String(opened))\n }\n if (!opened) {\n this.highlightedIndex = -1\n }\n }\n\n private onFocusOut = (e: FocusEvent) => {\n if (!this.element.contains(e.relatedTarget as Node)) {\n this.closeDropdown()\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────────────\n\n async connect (): Promise<void> {\n this.element.addEventListener('focusout', this.onFocusOut)\n\n const provider = this.providerValue\n const mapProv = this.effectiveMapProvider()\n\n if (!provider && !mapProv) return\n\n try {\n if (provider === 'mapkit') {\n await loadMapKitScript()\n this.initMapKit()\n } else if (provider === 'google') {\n await loadGoogleMapsScript(this.apiKeyValue)\n this.initGoogle()\n }\n // nominatim: no SDK to load\n\n // Pre-load Leaflet when it will be needed for the map preview\n if (this.showMapValue && mapProv === 'leaflet') {\n await loadLeafletScript()\n }\n } catch (err) {\n console.error('[midwest-address] Failed to initialise:', err)\n }\n }\n\n disconnect (): void {\n clearTimeout(this.searchTimer)\n this.element.removeEventListener('focusout', this.onFocusOut)\n if (this.mapInstance) {\n const mapProv = this.effectiveMapProvider()\n if (mapProv === 'mapkit') this.mapInstance.destroy()\n if (mapProv === 'leaflet') this.mapInstance.remove()\n }\n this.mapInstance = null\n }\n\n dropdownTargetConnected (el: HTMLElement) {\n el.addEventListener('toggle', this.onToggle)\n }\n\n dropdownTargetDisconnected (el: HTMLElement) {\n el.removeEventListener('toggle', this.onToggle)\n }\n\n // ── Public Stimulus actions ───────────────────────────────────────────────\n\n search (): void {\n this.clearGeocode()\n\n const query = this.inputTarget.value.trim()\n if (query.length < 2) {\n this.closeDropdown()\n return\n }\n\n clearTimeout(this.searchTimer)\n this.searchTimer = setTimeout(() => {\n if (this.providerValue === 'mapkit') {\n this.searchMapKit(query)\n } else if (this.providerValue === 'google') {\n this.searchGoogle(query)\n } else if (this.providerValue === 'nominatim') {\n this.searchNominatim(query)\n }\n }, DEBOUNCE_MS)\n }\n\n navigate (event: KeyboardEvent): void {\n const items = this.suggestionElements()\n if (!items.length) return\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault()\n this.highlightedIndex = Math.min(this.highlightedIndex + 1, items.length - 1)\n this.applyHighlight(items)\n break\n\n case 'ArrowUp':\n event.preventDefault()\n this.highlightedIndex = Math.max(this.highlightedIndex - 1, -1)\n this.applyHighlight(items)\n break\n\n case 'Enter':\n event.preventDefault()\n if (this.highlightedIndex >= 0) items[this.highlightedIndex].dispatchEvent(new MouseEvent('mousedown'))\n break\n\n case 'Escape':\n this.closeDropdown()\n break\n }\n }\n\n // ── Provider init ─────────────────────────────────────────────────────────\n\n private initMapKit (): void {\n const mk = (window as any).mapkit\n const { tokenValue: token, tokenUrlValue: tokenUrl } = this\n\n mk.init({\n authorizationCallback: (done: (t: string) => void) => {\n if (token) {\n done(token)\n } else if (tokenUrl) {\n fetch(tokenUrl)\n .then(r => r.text())\n .then(done)\n .catch(err => console.error('[midwest-address] Token fetch failed:', err))\n }\n },\n language: document.documentElement.lang || 'en'\n })\n\n this.mkSearch = new mk.Search({ getsUserLocation: false })\n }\n\n private initGoogle (): void {\n const g = (window as any).google\n this.autocompleteService = new g.maps.places.AutocompleteService()\n // PlacesService requires a DOM element or map instance; pass a detached div\n // so the component doesn't depend on a rendered map for detail fetches.\n this.placesService = new g.maps.places.PlacesService(document.createElement('div'))\n }\n\n // ── Search ────────────────────────────────────────────────────────────────\n\n private searchMapKit (query: string): void {\n if (!this.mkSearch) return\n\n this.mkSearch.autocomplete(query, (err: any, data: any) => {\n if (err || !data?.results?.length) {\n this.closeDropdown()\n return\n }\n\n const results: Suggestion[] = (data.results as any[]).map(r => ({\n id: r.completionURL ?? r.displayLines?.join(', ') ?? '',\n label: r.displayLines?.[0] ?? '',\n secondary: r.displayLines?.[1] ?? '',\n payload: r\n }))\n\n this.renderSuggestions(results)\n })\n }\n\n private searchGoogle (query: string): void {\n if (!this.autocompleteService) return\n\n const request: any = { input: query }\n if (this.countryCodesValue.length) {\n request.componentRestrictions = { country: this.countryCodesValue }\n }\n\n this.autocompleteService.getPlacePredictions(\n request,\n (predictions: any[] | null, status: string) => {\n const g = (window as any).google\n if (status !== g.maps.places.PlacesServiceStatus.OK || !predictions?.length) {\n this.closeDropdown()\n return\n }\n\n const results: Suggestion[] = predictions.map(p => ({\n id: p.place_id,\n label: p.structured_formatting?.main_text ?? p.description,\n secondary: p.structured_formatting?.secondary_text ?? '',\n payload: p\n }))\n\n this.renderSuggestions(results)\n }\n )\n }\n\n // ── Suggestions UI ────────────────────────────────────────────────────────\n\n private renderSuggestions (results: Suggestion[]): void {\n if (!this.hasSuggestionsTarget) return\n\n const list = this.suggestionsTarget\n list.innerHTML = ''\n\n results.forEach((r, i) => {\n const li = document.createElement('li')\n li.className = 'midwest-address__suggestion'\n li.setAttribute('role', 'option')\n li.setAttribute('id', `${this.element.id || 'addr'}-s${i}`)\n li.dataset.index = String(i)\n\n const main = document.createElement('span')\n main.className = 'midwest-address__suggestion-main'\n main.textContent = r.label\n li.appendChild(main)\n\n if (r.secondary) {\n const sec = document.createElement('span')\n sec.className = 'midwest-address__suggestion-secondary'\n sec.textContent = r.secondary\n li.appendChild(sec)\n }\n\n // mousedown fires before blur so the input doesn't lose focus before we\n // can read its value and fill the hidden fields.\n li.addEventListener('mousedown', (e) => {\n e.preventDefault()\n this.pickSuggestion(r)\n })\n\n list.appendChild(li)\n })\n\n this.openDropdown()\n this.highlightedIndex = -1\n }\n\n private openDropdown (): void {\n if (!this.hasDropdownTarget) return\n if (!this.dropdownTarget.matches(':popover-open')) this.dropdownTarget.showPopover()\n }\n\n private closeDropdown (): void {\n if (this.hasDropdownTarget && this.dropdownTarget.matches(':popover-open')) {\n this.dropdownTarget.hidePopover()\n }\n if (this.hasSuggestionsTarget) this.suggestionsTarget.innerHTML = ''\n this.highlightedIndex = -1\n }\n\n private suggestionElements (): HTMLLIElement[] {\n if (!this.hasSuggestionsTarget) return []\n return Array.from(this.suggestionsTarget.querySelectorAll<HTMLLIElement>('.midwest-address__suggestion'))\n }\n\n private applyHighlight (items: HTMLLIElement[]): void {\n items.forEach((item, i) => {\n const active = i === this.highlightedIndex\n item.classList.toggle('is-highlighted', active)\n item.setAttribute('aria-selected', String(active))\n if (active) {\n this.inputTarget.setAttribute('aria-activedescendant', item.id)\n item.scrollIntoView({ block: 'nearest' })\n }\n })\n if (this.highlightedIndex < 0) {\n this.inputTarget.removeAttribute('aria-activedescendant')\n }\n }\n\n // ── Pick a suggestion ─────────────────────────────────────────────────────\n\n private pickSuggestion (r: Suggestion): void {\n this.closeDropdown()\n\n if (this.providerValue === 'mapkit') {\n this.pickMapKit(r)\n } else if (this.providerValue === 'google') {\n this.pickGoogle(r)\n } else if (this.providerValue === 'nominatim') {\n this.pickNominatim(r)\n }\n }\n\n private pickMapKit (r: Suggestion): void {\n if (!this.mkSearch) return\n\n // Pass the raw completion object so MapKit resolves the exact place.\n this.mkSearch.search(r.payload, (err: any, data: any) => {\n if (err || !data?.places?.length) return\n\n const place = data.places[0]\n const coord = place.coordinate\n\n this.inputTarget.value = [r.label, r.secondary].filter(Boolean).join(', ')\n this.fillGeocode(coord.latitude, coord.longitude, place.id ?? '')\n this.updateMapPreview(coord.latitude, coord.longitude)\n })\n }\n\n private pickGoogle (r: Suggestion): void {\n if (!this.placesService || !r.id) return\n\n const g = (window as any).google\n this.placesService.getDetails(\n { placeId: r.id, fields: ['geometry', 'formatted_address', 'place_id'] },\n (place: any, status: string) => {\n if (status !== g.maps.places.PlacesServiceStatus.OK || !place) return\n\n const lat = place.geometry.location.lat()\n const lng = place.geometry.location.lng()\n\n this.inputTarget.value = place.formatted_address\n this.fillGeocode(lat, lng, place.place_id)\n this.updateMapPreview(lat, lng)\n }\n )\n }\n\n // ── Geocode field management ──────────────────────────────────────────────\n\n private fillGeocode (lat: number, lng: number, placeId: string): void {\n if (this.hasLatInputTarget) this.latInputTarget.value = String(lat)\n if (this.hasLngInputTarget) this.lngInputTarget.value = String(lng)\n if (this.hasPlaceIdInputTarget) this.placeIdInputTarget.value = placeId\n this.dispatch('geocode', { detail: { lat, lng, placeId } })\n }\n\n private clearGeocode (): void {\n if (this.hasLatInputTarget) this.latInputTarget.value = ''\n if (this.hasLngInputTarget) this.lngInputTarget.value = ''\n if (this.hasPlaceIdInputTarget) this.placeIdInputTarget.value = ''\n }\n\n // ── Nominatim search (OpenStreetMap, no API key) ──────────────────────────\n\n private searchNominatim (query: string): void {\n const base = this.nominatimUrlValue || 'https://nominatim.openstreetmap.org'\n const url = `${base}/search?q=${encodeURIComponent(query)}&format=json&limit=5&addressdetails=1`\n\n fetch(url, { headers: { 'Accept-Language': document.documentElement.lang || 'en' } })\n .then(r => r.json())\n .then((data: NominatimResult[]) => {\n if (!data?.length) { this.closeDropdown(); return }\n\n const results: Suggestion[] = data.map(r => {\n const parts = r.display_name.split(', ')\n return {\n id: String(r.place_id),\n label: r.name || parts[0] || r.display_name,\n secondary: parts.length > 1 ? parts.slice(1).join(', ') : '',\n payload: r\n }\n })\n\n this.renderSuggestions(results)\n })\n .catch(() => this.closeDropdown())\n }\n\n private pickNominatim (r: Suggestion): void {\n const place = r.payload as NominatimResult\n const lat = parseFloat(place.lat)\n const lng = parseFloat(place.lon)\n\n this.inputTarget.value = place.display_name\n this.fillGeocode(lat, lng, `${place.osm_type}:${place.osm_id}`)\n this.updateMapPreview(lat, lng)\n }\n\n // ── Map preview ───────────────────────────────────────────────────────────\n\n // Returns the provider used for the map preview. `mapProviderValue` is set\n // when the geocoder and map providers differ; falls back to `providerValue`\n // so existing single-provider setups (mapkit/google) work without change.\n private effectiveMapProvider (): string {\n return this.mapProviderValue || this.providerValue\n }\n\n private updateMapPreview (lat: number, lng: number): void {\n if (!this.hasMapContainerTarget || !this.showMapValue) return\n\n this.mapContainerTarget.hidden = false\n\n const mapProv = this.effectiveMapProvider()\n if (mapProv === 'mapkit') {\n this.updateMapKitPreview(lat, lng)\n } else if (mapProv === 'google') {\n this.updateGooglePreview(lat, lng)\n } else if (mapProv === 'leaflet') {\n this.updateLeafletPreview(lat, lng)\n }\n }\n\n private updateMapKitPreview (lat: number, lng: number): void {\n const mk = (window as any).mapkit\n const coord = new mk.Coordinate(lat, lng)\n\n if (!this.mapInstance) {\n this.mapInstance = new mk.Map(this.mapContainerTarget, {\n mapType: mk.Map.MapTypes.MutedStandard,\n showsCompass: mk.FeatureVisibility.Hidden,\n showsZoomControl: false,\n showsMapTypeControl: false,\n isScrollEnabled: false,\n isZoomEnabled: false\n })\n }\n\n this.mapInstance.setRegionAnimated(\n new mk.CoordinateRegion(coord, new mk.CoordinateSpan(0.01, 0.01))\n )\n\n if (this.mapMarker) this.mapInstance.removeAnnotation(this.mapMarker)\n this.mapMarker = new mk.MarkerAnnotation(coord)\n this.mapInstance.addAnnotation(this.mapMarker)\n }\n\n private updateGooglePreview (lat: number, lng: number): void {\n const g = (window as any).google\n const center = { lat, lng }\n\n if (!this.mapInstance) {\n this.mapInstance = new g.maps.Map(this.mapContainerTarget, {\n center,\n zoom: 15,\n disableDefaultUI: true,\n gestureHandling: 'none',\n styles: GOOGLE_PREVIEW_STYLES\n })\n } else {\n this.mapInstance.setCenter(center)\n this.mapInstance.setZoom(15)\n }\n\n if (this.mapMarker) this.mapMarker.setMap(null)\n this.mapMarker = new g.maps.Marker({ map: this.mapInstance, position: center })\n }\n\n private updateLeafletPreview (lat: number, lng: number): void {\n const L = (window as any).L\n if (!L) return\n\n if (!this.mapInstance) {\n this.mapInstance = L.map(this.mapContainerTarget, {\n center: [lat, lng],\n zoom: 15,\n zoomControl: false,\n attributionControl: false\n })\n L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {\n maxZoom: 19\n }).addTo(this.mapInstance)\n } else {\n this.mapInstance.setView([lat, lng], 15)\n }\n\n if (this.mapMarker) this.mapMarker.remove()\n this.mapMarker = L.marker([lat, lng]).addTo(this.mapInstance)\n }\n}\n"],"names":[],"mappings":"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"}
@@ -16,6 +16,7 @@ class FormLiveSummary extends Controller {
16
16
  this.form?.addEventListener("midwest-autocomplete:change", this.render);
17
17
  this.form?.addEventListener("midwest-color-picker:update", this.render);
18
18
  this.form?.addEventListener("midwest-repeatable:change", this.render);
19
+ this.form?.addEventListener("midwest-address:geocode", this.render);
19
20
  }
20
21
  disconnect() {
21
22
  this.form?.removeEventListener("input", this.render);
@@ -23,6 +24,7 @@ class FormLiveSummary extends Controller {
23
24
  this.form?.removeEventListener("midwest-autocomplete:change", this.render);
24
25
  this.form?.removeEventListener("midwest-color-picker:update", this.render);
25
26
  this.form?.removeEventListener("midwest-repeatable:change", this.render);
27
+ this.form?.removeEventListener("midwest-address:geocode", this.render);
26
28
  }
27
29
  get form() {
28
30
  return this.element.closest("form");
@@ -40,7 +42,7 @@ class FormLiveSummary extends Controller {
40
42
  }
41
43
  const dl = document.createElement("dl");
42
44
  dl.className = "midwest-form-live-summary-list";
43
- fields.forEach(({ label, value, swatchColor }) => {
45
+ fields.forEach(({ label, value, swatchColor, details }) => {
44
46
  const dt = Object.assign(document.createElement("dt"), {
45
47
  className: "midwest-form-live-summary-term",
46
48
  textContent: label
@@ -49,6 +51,8 @@ class FormLiveSummary extends Controller {
49
51
  dd.className = "midwest-form-live-summary-definition";
50
52
  if (swatchColor !== void 0) {
51
53
  dd.append(this.buildSwatch(swatchColor), value || "\u2014");
54
+ } else if (details && Object.keys(details).length > 0) {
55
+ dd.append(this.buildGeocode(value || "\u2014", details));
52
56
  } else {
53
57
  dd.textContent = value || "\u2014";
54
58
  }
@@ -76,6 +80,8 @@ class FormLiveSummary extends Controller {
76
80
  return;
77
81
  if (element.closest(".midwest-repeatable"))
78
82
  return;
83
+ if (element.closest(".midwest-address"))
84
+ return;
79
85
  if (element instanceof HTMLInputElement) {
80
86
  if (SKIPPED_INPUT_TYPES.has(element.type))
81
87
  return;
@@ -195,6 +201,29 @@ class FormLiveSummary extends Controller {
195
201
  });
196
202
  });
197
203
  });
204
+ form.querySelectorAll(".midwest-address").forEach((addr) => {
205
+ if (this.element.contains(addr))
206
+ return;
207
+ const input = addr.querySelector('[data-midwest-address-target="input"]');
208
+ const latInput = addr.querySelector('[data-midwest-address-target="latInput"]');
209
+ const lngInput = addr.querySelector('[data-midwest-address-target="lngInput"]');
210
+ const placeIdInput = addr.querySelector('[data-midwest-address-target="placeIdInput"]');
211
+ const labelEl = addr.querySelector(".midwest-form-group__top label");
212
+ const label = labelEl?.textContent?.trim() || this.prettifyName((input?.name ?? latInput?.name?.replace(/_latitude$/, "") ?? "").replace(/\[.*\]$/, ""));
213
+ const value = input?.value?.trim() || "";
214
+ const details = {};
215
+ if (latInput?.value)
216
+ details["Latitude"] = latInput.value;
217
+ if (lngInput?.value)
218
+ details["Longitude"] = lngInput.value;
219
+ if (placeIdInput?.value)
220
+ details["Place ID"] = placeIdInput.value;
221
+ fields.push({
222
+ label,
223
+ value: value || "\u2014",
224
+ details: Object.keys(details).length > 0 ? details : void 0
225
+ });
226
+ });
198
227
  return fields;
199
228
  }
200
229
  // Builds a small inline colour swatch to display alongside a colour value.
@@ -213,6 +242,31 @@ class FormLiveSummary extends Controller {
213
242
  }
214
243
  return swatch;
215
244
  }
245
+ // Wraps an address value in a span that reveals a geocode detail popup on hover.
246
+ buildGeocode(value, details) {
247
+ const wrapper = document.createElement("span");
248
+ wrapper.className = "midwest-form-live-summary-geocode";
249
+ const text = document.createElement("span");
250
+ text.className = "midwest-form-live-summary-geocode-text";
251
+ text.textContent = value;
252
+ const popup = document.createElement("span");
253
+ popup.className = "midwest-form-live-summary-geocode-popup";
254
+ popup.setAttribute("aria-hidden", "true");
255
+ Object.entries(details).forEach(([key, val]) => {
256
+ const row = document.createElement("span");
257
+ row.className = "midwest-form-live-summary-geocode-row";
258
+ const keyEl = document.createElement("span");
259
+ keyEl.className = "midwest-form-live-summary-geocode-key";
260
+ keyEl.textContent = key;
261
+ const valEl = document.createElement("span");
262
+ valEl.className = "midwest-form-live-summary-geocode-val";
263
+ valEl.textContent = val;
264
+ row.append(keyEl, valEl);
265
+ popup.append(row);
266
+ });
267
+ wrapper.append(text, popup);
268
+ return wrapper;
269
+ }
216
270
  // Finds the label associated with a specific element via `for` attribute,
217
271
  // wrapping label, or falls back to a prettified version of the element name.
218
272
  labelFor(el) {