@fieldia/map 0.0.0-stage → 0.14.1

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 (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +98 -2
  3. package/package.json +37 -3
  4. package/src/index.d.mts +6 -0
  5. package/src/index.d.ts +6 -0
  6. package/src/index.js +22 -0
  7. package/src/index.js.map +1 -0
  8. package/src/index.mjs +6 -0
  9. package/src/index.mjs.map +1 -0
  10. package/src/lib/area.d.mts +3 -0
  11. package/src/lib/area.d.ts +3 -0
  12. package/src/lib/area.js +591 -0
  13. package/src/lib/area.js.map +1 -0
  14. package/src/lib/area.mjs +588 -0
  15. package/src/lib/area.mjs.map +1 -0
  16. package/src/lib/geo.d.mts +72 -0
  17. package/src/lib/geo.d.ts +72 -0
  18. package/src/lib/geo.js +149 -0
  19. package/src/lib/geo.js.map +1 -0
  20. package/src/lib/geo.mjs +134 -0
  21. package/src/lib/geo.mjs.map +1 -0
  22. package/src/lib/kinds.d.mts +35 -0
  23. package/src/lib/kinds.d.ts +35 -0
  24. package/src/lib/kinds.js +127 -0
  25. package/src/lib/kinds.js.map +1 -0
  26. package/src/lib/kinds.mjs +124 -0
  27. package/src/lib/kinds.mjs.map +1 -0
  28. package/src/lib/labels.d.mts +62 -0
  29. package/src/lib/labels.d.ts +62 -0
  30. package/src/lib/labels.js +226 -0
  31. package/src/lib/labels.js.map +1 -0
  32. package/src/lib/labels.mjs +221 -0
  33. package/src/lib/labels.mjs.map +1 -0
  34. package/src/lib/leaflet-css.d.mts +2 -0
  35. package/src/lib/leaflet-css.d.ts +2 -0
  36. package/src/lib/leaflet-css.js +34 -0
  37. package/src/lib/leaflet-css.js.map +1 -0
  38. package/src/lib/leaflet-css.mjs +31 -0
  39. package/src/lib/leaflet-css.mjs.map +1 -0
  40. package/src/lib/leaflet.d.mts +15 -0
  41. package/src/lib/leaflet.d.ts +15 -0
  42. package/src/lib/leaflet.js +76 -0
  43. package/src/lib/leaflet.js.map +1 -0
  44. package/src/lib/leaflet.mjs +72 -0
  45. package/src/lib/leaflet.mjs.map +1 -0
  46. package/src/lib/map-core.d.mts +49 -0
  47. package/src/lib/map-core.d.ts +49 -0
  48. package/src/lib/map-core.js +312 -0
  49. package/src/lib/map-core.js.map +1 -0
  50. package/src/lib/map-core.mjs +308 -0
  51. package/src/lib/map-core.mjs.map +1 -0
  52. package/src/lib/place.d.mts +3 -0
  53. package/src/lib/place.d.ts +3 -0
  54. package/src/lib/place.js +363 -0
  55. package/src/lib/place.js.map +1 -0
  56. package/src/lib/place.mjs +360 -0
  57. package/src/lib/place.mjs.map +1 -0
  58. package/src/lib/providers.d.mts +152 -0
  59. package/src/lib/providers.d.ts +152 -0
  60. package/src/lib/providers.js +408 -0
  61. package/src/lib/providers.js.map +1 -0
  62. package/src/lib/providers.mjs +401 -0
  63. package/src/lib/providers.mjs.map +1 -0
  64. package/src/lib/search-box.d.mts +30 -0
  65. package/src/lib/search-box.d.ts +30 -0
  66. package/src/lib/search-box.js +155 -0
  67. package/src/lib/search-box.js.map +1 -0
  68. package/src/lib/search-box.mjs +152 -0
  69. package/src/lib/search-box.mjs.map +1 -0
  70. package/src/lib/settings.d.mts +19 -0
  71. package/src/lib/settings.d.ts +19 -0
  72. package/src/lib/settings.js +3 -0
  73. package/src/lib/settings.js.map +1 -0
  74. package/src/lib/settings.mjs +2 -0
  75. package/src/lib/settings.mjs.map +1 -0
  76. package/src/lib/styles.d.mts +11 -0
  77. package/src/lib/styles.d.ts +11 -0
  78. package/src/lib/styles.js +130 -0
  79. package/src/lib/styles.js.map +1 -0
  80. package/src/lib/styles.mjs +125 -0
  81. package/src/lib/styles.mjs.map +1 -0
  82. package/src/lib/widgets.d.mts +14 -0
  83. package/src/lib/widgets.d.ts +14 -0
  84. package/src/lib/widgets.js +21 -0
  85. package/src/lib/widgets.js.map +1 -0
  86. package/src/lib/widgets.mjs +18 -0
  87. package/src/lib/widgets.mjs.map +1 -0
@@ -0,0 +1,360 @@
1
+ import { formatNumber } from '@fieldia/widgets';
2
+ import { asJson, isLatLng, parseCoordinate, readPoint, writePoint } from './geo.mjs';
3
+ import { fill, mapLabels } from './labels.mjs';
4
+ import { createMapBox, warnOnce } from './map-core.mjs';
5
+ import { searchBox } from './search-box.mjs';
6
+ /**
7
+ * A place on a form: a click on the map, a dragged pin, an address found,
8
+ * or "My location". Kept as a GeoJSON Point in a json field, or in two
9
+ * number fields (`latitude` with `options.longitudeField`), the way Odoo
10
+ * keeps a partner's place. The coordinates stay typeable under the map:
11
+ * that is the way in without a mouse, beside Enter on the map (the place
12
+ * at its centre) and the arrow keys on the pin.
13
+ *
14
+ * Options: `longitudeField`, `addressField` (filled from the address
15
+ * found, or named from the point where the provider can), `myLocation`
16
+ * (on unless false), `search` (on unless false), `zoom` (15), `height`.
17
+ */
18
+ const PIN = `<svg viewBox="0 0 28 40" aria-hidden="true"><path class="fd-map-pin-body" d="M14 1C6.8 1 1 6.7 1 13.8 1 23.6 14 39 14 39s13-15.4 13-25.2C27 6.7 21.2 1 14 1z"/><circle class="fd-map-pin-dot" cx="14" cy="14" r="5"/></svg>`;
19
+ const round6 = (n) => Math.round(n * 1e6) / 1e6;
20
+ export function placeWidget(settings) {
21
+ return (context) => {
22
+ const { form, name, field, node, id, document: doc } = context;
23
+ const options = node.options ?? {};
24
+ const labels = mapLabels(context.locale, settings.labels?.[context.locale ?? 'en']);
25
+ const longitudeField = typeof options['longitudeField'] === 'string' ? options['longitudeField'] : null;
26
+ const addressField = typeof options['addressField'] === 'string' ? options['addressField'] : null;
27
+ const inFields = field.type === 'float';
28
+ if (inFields && !longitudeField)
29
+ throw new Error(`The place on "${name}" keeps its latitude there and needs options.longitudeField for its longitude`);
30
+ const zoom = typeof options['zoom'] === 'number' ? options['zoom'] : 15;
31
+ const search = options['search'] === false ? undefined : (settings.search ?? settings.provider.search);
32
+ const reverse = settings.reverse ?? settings.provider.reverse;
33
+ const asYouType = settings.search ? (settings.searchAsYouType ?? true) : !!settings.provider.searchAsYouType;
34
+ const geolocation = options['myLocation'] === false ? undefined : doc.defaultView?.navigator.geolocation;
35
+ let readonly = false;
36
+ let point = null;
37
+ /** The address this field last wrote: one a person typed is never written over. */
38
+ let addressWritten;
39
+ let values = form.getState().values;
40
+ const element = doc.createElement('div');
41
+ element.className = 'fd-map-field fd-place';
42
+ element.setAttribute('role', 'group');
43
+ element.setAttribute('aria-labelledby', `${id}-label`);
44
+ const tools = doc.createElement('div');
45
+ tools.className = 'fd-map-tools';
46
+ const note = doc.createElement('p');
47
+ note.className = 'fd-map-note';
48
+ note.setAttribute('aria-live', 'polite');
49
+ note.hidden = true;
50
+ const say = (words, tone) => {
51
+ note.textContent = words ?? '';
52
+ note.hidden = !words;
53
+ if (tone)
54
+ note.dataset['tone'] = tone;
55
+ else
56
+ delete note.dataset['tone'];
57
+ };
58
+ const box = createMapBox({
59
+ document: doc,
60
+ provider: settings.provider,
61
+ locale: context.locale ?? 'en',
62
+ labels,
63
+ name: field.label,
64
+ keys: labels.placeKeys,
65
+ center: settings.center,
66
+ zoom: settings.center ? (settings.zoom ?? 11) : undefined,
67
+ height: typeof options['height'] === 'number' ? options['height'] : undefined,
68
+ });
69
+ // ---- the coordinates, typeable -------------------------------------------
70
+ const coords = doc.createElement('div');
71
+ coords.className = 'fd-map-coords';
72
+ const coordinate = (words, inputId) => {
73
+ const label = doc.createElement('label');
74
+ const input = doc.createElement('input');
75
+ input.className = 'fd-input';
76
+ input.id = inputId;
77
+ input.inputMode = 'decimal';
78
+ input.autocomplete = 'off';
79
+ input.spellcheck = false;
80
+ label.append(words, input);
81
+ coords.append(label);
82
+ return input;
83
+ };
84
+ const lat = coordinate(labels.latitude, search ? `${id}-lat` : id);
85
+ const lng = coordinate(labels.longitude, `${id}-lng`);
86
+ const typed = () => {
87
+ const a = parseCoordinate(lat.value);
88
+ const b = parseCoordinate(lng.value);
89
+ const empty = !lat.value.trim() && !lng.value.trim();
90
+ const good = empty || isLatLng(a, b);
91
+ lat.setAttribute('aria-invalid', String(!good || (a !== null && Math.abs(a) > 90)));
92
+ lng.setAttribute('aria-invalid', String(!good || (b !== null && Math.abs(b) > 180)));
93
+ if (!good)
94
+ return say(labels.notACoordinate, 'error');
95
+ say(null);
96
+ if (empty)
97
+ return set(null);
98
+ set({ lat: a, lng: b }, { fly: true, name: true });
99
+ };
100
+ for (const input of [lat, lng]) {
101
+ input.addEventListener('change', typed);
102
+ input.addEventListener('keydown', (event) => event.key === 'Enter' && (event.preventDefault(), typed()));
103
+ }
104
+ // ---- writing ---------------------------------------------------------------
105
+ function write(next) {
106
+ if (inFields) {
107
+ form.setValue(name, next ? round6(next.lat) : null);
108
+ form.setValue(longitudeField, next ? round6(next.lng) : null);
109
+ }
110
+ else
111
+ form.setValue(name, next ? asJson(writePoint(next)) : null);
112
+ }
113
+ let naming = null;
114
+ /** The address from the point, where the provider can say one, unless a person typed their own. */
115
+ function nameFrom(at) {
116
+ if (!addressField || !reverse)
117
+ return;
118
+ const current = values[addressField];
119
+ if (current !== null && current !== undefined && current !== '' && current !== addressWritten)
120
+ return;
121
+ naming?.abort();
122
+ naming = new AbortController();
123
+ reverse({ ...at, locale: context.locale ?? 'en', signal: naming.signal })
124
+ .then((label) => {
125
+ if (!label)
126
+ return;
127
+ addressWritten = label;
128
+ form.setValue(addressField, label);
129
+ })
130
+ .catch((error) => error.name !== 'AbortError' && warnOnce(`Naming the place failed: ${error.message}`));
131
+ }
132
+ function set(next, how = {}) {
133
+ if (readonly)
134
+ return;
135
+ // How sure "My location" was: a circle while the place is the one it gave.
136
+ showAccuracy(next && how.within !== undefined ? { at: next, metres: how.within } : null);
137
+ if (next)
138
+ next = { lat: round6(next.lat), lng: round6(next.lng) };
139
+ point = next;
140
+ show(how.fly);
141
+ write(next);
142
+ if (next && how.address !== undefined && addressField) {
143
+ addressWritten = how.address;
144
+ form.setValue(addressField, how.address);
145
+ }
146
+ else if (next && how.name)
147
+ nameFrom(next);
148
+ }
149
+ // ---- the map and its pin ---------------------------------------------------
150
+ let marker = null;
151
+ let accuracy = null;
152
+ /** The map, once it is there: where it is and how close, for the search's "near". */
153
+ let shown = null;
154
+ /** The circle a rough location may be anywhere in, fitted into view; a desktop's is often kilometres wide. */
155
+ function showAccuracy(within) {
156
+ box.ready((map, L) => {
157
+ accuracy?.remove();
158
+ accuracy = null;
159
+ if (!within)
160
+ return;
161
+ accuracy = L.circle([within.at.lat, within.at.lng], { radius: within.metres, className: 'fd-map-accuracy', interactive: false }).addTo(map);
162
+ map.fitBounds(accuracy.getBounds(), { padding: [24, 24], maxZoom: zoom });
163
+ });
164
+ }
165
+ function show(fly = false) {
166
+ clear.hidden = readonly || !point;
167
+ box.ready((map, L) => {
168
+ if (!point) {
169
+ marker?.remove();
170
+ marker = null;
171
+ return;
172
+ }
173
+ const at = [point.lat, point.lng];
174
+ if (!marker)
175
+ marker = makeMarker(map, L, at);
176
+ else
177
+ marker.setLatLng(at);
178
+ if (marker.dragging) {
179
+ if (readonly)
180
+ marker.dragging.disable();
181
+ else
182
+ marker.dragging.enable();
183
+ }
184
+ marker.getElement()?.setAttribute('aria-label', `${field.label}: ${point.lat}, ${point.lng}`);
185
+ if (fly)
186
+ map.setView(at, Math.max(map.getZoom(), zoom));
187
+ // A rough location's circle has fitted the map already.
188
+ else if (!accuracy && !map.getBounds().contains(at))
189
+ map.setView(at, map.getZoom() < 5 ? zoom : map.getZoom());
190
+ });
191
+ }
192
+ function makeMarker(map, L, at) {
193
+ const icon = L.divIcon({ className: 'fd-map-pin', html: PIN, iconSize: [28, 40], iconAnchor: [14, 39] });
194
+ const pin = L.marker(at, { icon, draggable: !readonly, keyboard: true, autoPan: true }).addTo(map);
195
+ pin.on('dragend', () => {
196
+ const moved = pin.getLatLng();
197
+ set({ lat: moved.lat, lng: moved.lng }, { name: true });
198
+ });
199
+ // The arrow keys carry the pin a few pixels; Shift, further.
200
+ pin.getElement()?.addEventListener('keydown', (event) => {
201
+ const step = event.shiftKey ? 16 : 4;
202
+ const by = { ArrowUp: [0, -step], ArrowDown: [0, step], ArrowLeft: [-step, 0], ArrowRight: [step, 0] }[event.key];
203
+ if (!by || readonly)
204
+ return;
205
+ event.preventDefault();
206
+ event.stopPropagation();
207
+ const there = map.containerPointToLatLng(map.latLngToContainerPoint(pin.getLatLng()).add(L.point(by[0], by[1])));
208
+ set({ lat: there.lat, lng: there.lng }, { name: true });
209
+ });
210
+ return pin;
211
+ }
212
+ box.ready((map) => {
213
+ shown = map;
214
+ map.on('click', (event) => set({ lat: event.latlng.lat, lng: event.latlng.lng }, { name: true }));
215
+ // Enter on the map: the place at its centre, where the cross is.
216
+ box.element.addEventListener('keydown', (event) => {
217
+ if ((event.key !== 'Enter' && event.key !== ' ') || event.target !== box.element || readonly)
218
+ return;
219
+ event.preventDefault();
220
+ const centre = map.getCenter();
221
+ set({ lat: centre.lat, lng: centre.lng }, { name: true });
222
+ });
223
+ show(true);
224
+ });
225
+ /** "3 km", "400 m", in the page's language and its way of writing numbers. */
226
+ const distance = (metres) => metres >= 1000 ? fill(labels.kilometres, { n: formatNumber(Math.round(metres / 1000), 0, context.locale ?? 'en') }) : fill(labels.metres, { n: formatNumber(Math.round(metres / 10) * 10, 0, context.locale ?? 'en') });
227
+ // ---- search, my location, clear ---------------------------------------------
228
+ const found = search
229
+ ? searchBox({
230
+ document: doc,
231
+ id: lat.id === id ? `${id}-search` : id,
232
+ labels,
233
+ search,
234
+ asYouType: asYouType,
235
+ locale: context.locale ?? 'en',
236
+ // Nearest where the map is looking first, as a map's own search does.
237
+ near: () => {
238
+ const centre = shown?.getCenter();
239
+ return centre ? { lat: centre.lat, lng: centre.lng } : (point ?? settings.center);
240
+ },
241
+ zoom: () => shown?.getZoom(),
242
+ // A place picked: where it is (looked up now, when the provider's suggestions carry no place), and its whole address for Address.
243
+ pick: async (place) => {
244
+ const located = place.lat !== undefined && place.lng !== undefined
245
+ ? { lat: place.lat, lng: place.lng, address: undefined }
246
+ : await place.locate?.().catch((error) => (warnOnce(`Finding the place picked failed: ${error.message}`), null));
247
+ if (!located)
248
+ return say(labels.searchFailed, 'error');
249
+ set({ lat: located.lat, lng: located.lng }, { fly: true, address: located.address ?? [place.label, place.detail].filter(Boolean).join(', ') });
250
+ },
251
+ say,
252
+ })
253
+ : null;
254
+ if (found)
255
+ tools.append(found.element);
256
+ const myLocation = doc.createElement('button');
257
+ myLocation.type = 'button';
258
+ myLocation.className = 'fd-button';
259
+ myLocation.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3"/></svg>';
260
+ myLocation.append(labels.myLocation);
261
+ let blocked = false;
262
+ myLocation.hidden = !geolocation;
263
+ myLocation.addEventListener('click', () => {
264
+ if (!geolocation)
265
+ return;
266
+ say(labels.locating);
267
+ geolocation.getCurrentPosition((position) => {
268
+ const metres = Math.round(position.coords.accuracy);
269
+ // Named only when it is sure: an address from a point kilometres off would be someone else's.
270
+ set({ lat: position.coords.latitude, lng: position.coords.longitude }, { name: metres <= 100, within: metres });
271
+ // A rough location says how rough: a desktop's comes from its network, and may be a city away.
272
+ if (metres > 100)
273
+ say(fill(labels.locatedWithin, { distance: distance(metres) }));
274
+ else
275
+ say(null);
276
+ }, (error) => {
277
+ if (error.code === error.PERMISSION_DENIED) {
278
+ blocked = true;
279
+ myLocation.hidden = true;
280
+ say(labels.locationBlocked);
281
+ }
282
+ else
283
+ say(labels.locationFailed, 'error');
284
+ }, { enableHighAccuracy: true, timeout: 10_000, maximumAge: 60_000 });
285
+ });
286
+ // Location blocked for the site: the button goes, with the reason in its place.
287
+ doc.defaultView?.navigator.permissions
288
+ ?.query({ name: 'geolocation' })
289
+ .then((status) => {
290
+ const read = () => {
291
+ blocked = status.state === 'denied';
292
+ myLocation.hidden = !geolocation || blocked || readonly;
293
+ if (blocked)
294
+ say(labels.locationBlocked);
295
+ };
296
+ read();
297
+ status.onchange = read;
298
+ })
299
+ .catch(() => undefined);
300
+ const clear = doc.createElement('button');
301
+ clear.type = 'button';
302
+ clear.className = 'fd-button fd-button-link';
303
+ clear.textContent = labels.clear;
304
+ clear.hidden = true;
305
+ clear.addEventListener('click', () => {
306
+ set(null);
307
+ say(null);
308
+ (found?.input ?? lat).focus();
309
+ });
310
+ tools.append(myLocation, clear);
311
+ element.append(tools, box.element, coords, note);
312
+ const showCoords = () => {
313
+ for (const [input, n] of [[lat, point?.lat], [lng, point?.lng]]) {
314
+ if (doc.activeElement === input)
315
+ continue;
316
+ input.value = n === undefined ? '' : String(n);
317
+ input.setAttribute('aria-invalid', 'false');
318
+ }
319
+ };
320
+ return {
321
+ element,
322
+ focus: () => (found?.input ?? lat).focus(),
323
+ destroy: () => {
324
+ naming?.abort();
325
+ found?.destroy();
326
+ box.destroy();
327
+ },
328
+ update(state) {
329
+ values = state.values;
330
+ readonly = state.readonly;
331
+ const next = inFields
332
+ ? isLatLng(state.value, state.values[longitudeField])
333
+ ? { lat: state.value, lng: state.values[longitudeField] }
334
+ : null
335
+ : readPoint(state.value);
336
+ const changed = next?.lat !== point?.lat || next?.lng !== point?.lng;
337
+ point = next;
338
+ tools.hidden = readonly;
339
+ myLocation.hidden = !geolocation || blocked || readonly;
340
+ for (const input of [lat, lng])
341
+ input.readOnly = readonly;
342
+ const target = found?.input ?? lat;
343
+ target.setAttribute('aria-invalid', String(state.invalid));
344
+ target.setAttribute('aria-required', String(state.required));
345
+ if (state.describedBy)
346
+ target.setAttribute('aria-describedby', state.describedBy);
347
+ else
348
+ target.removeAttribute('aria-describedby');
349
+ lat.setAttribute('aria-required', String(state.required));
350
+ showCoords();
351
+ box.refresh();
352
+ if (changed)
353
+ show();
354
+ else
355
+ clear.hidden = readonly || !point;
356
+ },
357
+ };
358
+ };
359
+ }
360
+ //# sourceMappingURL=place.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"place.mjs","sourceRoot":"","sources":["../../../../../libs/map/src/lib/place.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,152 @@
1
+ import type { Locale } from '@fieldia/core';
2
+ import type { Bounds, LatLng } from './geo.mjs';
3
+ /**
4
+ * Where a map's images, credits and address search come from. Every map in
5
+ * the package draws through one of these, so an app changes provider in one
6
+ * place and nothing else moves. Keys never live in Fieldia: the app passes
7
+ * them, or a function that fetches a short-lived token from its own server.
8
+ * Credits are text and links built here, never HTML from a provider.
9
+ */
10
+ export type BaseMap = 'road' | 'dark' | 'satellite';
11
+ export interface TileSpec {
12
+ /** With `{z}`, `{x}` and `{y}` where the tile's numbers go. */
13
+ url: string;
14
+ maxZoom: number;
15
+ tileSize?: number;
16
+ zoomOffset?: number;
17
+ /** Headers each image is fetched with: a token that must not sit in an address. */
18
+ headers?: () => Promise<Record<string, string>>;
19
+ }
20
+ export interface Credit {
21
+ text: string;
22
+ href?: string;
23
+ }
24
+ export interface MapView {
25
+ zoom: number;
26
+ bounds: Bounds;
27
+ }
28
+ export interface PlaceFound {
29
+ /** The place itself: a name, or a street and its number. */
30
+ label: string;
31
+ /** Where it is, on the line under it: its district, city, country. */
32
+ detail?: string;
33
+ /** Where it is on the map; or, for a provider whose suggestions carry none (Google's), `locate` finds it when the place is picked. */
34
+ lat?: number;
35
+ lng?: number;
36
+ locate?: () => Promise<{
37
+ lat: number;
38
+ lng: number;
39
+ address?: string;
40
+ }>;
41
+ }
42
+ export interface SearchRequest {
43
+ text: string;
44
+ /** Where the map is: results near it first. */
45
+ near?: LatLng;
46
+ /** How close the map is, for how far "near" reaches. */
47
+ zoom?: number;
48
+ locale: Locale;
49
+ signal?: AbortSignal;
50
+ }
51
+ export type AddressSearch = (request: SearchRequest) => Promise<PlaceFound[]>;
52
+ export type ReverseSearch = (at: LatLng & {
53
+ locale: Locale;
54
+ signal?: AbortSignal;
55
+ }) => Promise<string | null>;
56
+ export interface MapProvider {
57
+ readonly id: string;
58
+ /** The map images of a kind, or null when the provider has none of it. */
59
+ tiles(kind: BaseMap, locale: Locale): Promise<TileSpec | null>;
60
+ /** What must be credited under the map, for what is in view. */
61
+ credits(kind: BaseMap, view: MapView, locale: Locale): Promise<Credit[]>;
62
+ /** The provider's mark, which its terms ask for in the map's corner. */
63
+ readonly logo?: {
64
+ text: string;
65
+ image?: string;
66
+ href?: string;
67
+ };
68
+ readonly search?: AddressSearch;
69
+ readonly reverse?: ReverseSearch;
70
+ /** Whether its terms allow a search for each pause in typing; otherwise it searches when Enter is pressed. */
71
+ readonly searchAsYouType?: boolean;
72
+ /** Free for trying things out, not for an app in use: a warning says so once. */
73
+ readonly demoOnly?: boolean;
74
+ }
75
+ type Fetch = typeof globalThis.fetch;
76
+ export interface OpenStreetMapOptions {
77
+ /**
78
+ * Whose search: Photon (komoot's, on OpenStreetMap's data), which answers as
79
+ * people type, nearest the map first; or Nominatim, OpenStreetMap's own,
80
+ * whose policy allows a search only when Enter is pressed.
81
+ */
82
+ search?: 'photon' | 'nominatim';
83
+ /** Photon's address, for a copy of it the app runs: `https://photon.komoot.io` unless said. */
84
+ photonUrl?: string;
85
+ fetch?: Fetch;
86
+ }
87
+ /**
88
+ * OpenStreetMap's own map images, for demos and development only (its usage
89
+ * policy treats an app in production as heavy use), with Photon's search,
90
+ * which answers as people type, or Nominatim's.
91
+ */
92
+ export declare function openStreetMap(options?: OpenStreetMapOptions): MapProvider;
93
+ export interface AzureMapsOptions {
94
+ /** A subscription key, restricted to the app's sites in Azure. */
95
+ key?: string;
96
+ /** Or a Microsoft Entra token, fetched from the app's own server; sent in a header with `clientId`. */
97
+ token?: () => Promise<string>;
98
+ clientId?: string;
99
+ fetch?: Fetch;
100
+ }
101
+ /** Microsoft Azure Maps: road, dark and satellite map images, credits for the view, and address search. */
102
+ export declare function azureMaps(options: AzureMapsOptions): MapProvider;
103
+ export interface GoogleMapsOptions {
104
+ key: string;
105
+ /** The country whose borders and names the map follows (CLDR, such as `EG`). */
106
+ region?: string;
107
+ /** Google's logo, as an image the app serves; its name is shown in its place until one is given. */
108
+ logo?: string;
109
+ fetch?: Fetch;
110
+ }
111
+ /**
112
+ * Google's map images through its Map Tiles API (a session for each kind and
113
+ * language, credits for the view, Google's mark in the corner its terms
114
+ * name), its Places API's suggestions as people type, and its Geocoding API
115
+ * to name a point. The key needs those three APIs enabled, and should be
116
+ * restricted to the app's sites.
117
+ */
118
+ export declare function googleMaps(options: GoogleMapsOptions): MapProvider;
119
+ export interface MapboxOptions {
120
+ token: string;
121
+ /** Style ids, `owner/style`. */
122
+ style?: string;
123
+ darkStyle?: string;
124
+ satelliteStyle?: string;
125
+ /** Mapbox's wordmark, as an image the app serves; its name is shown until one is given. */
126
+ logo?: string;
127
+ /**
128
+ * Ask for results the app may keep (Mapbox's permanent geocoding). On by
129
+ * default, because a place field keeps what it finds; off only for an app
130
+ * that stores nothing.
131
+ */
132
+ permanent?: boolean;
133
+ fetch?: Fetch;
134
+ }
135
+ /** Mapbox: its styles as map images, its credits and wordmark, and its address search as people type. */
136
+ export declare function mapbox(options: MapboxOptions): MapProvider;
137
+ export interface TilesOptions {
138
+ /** With `{z}`, `{x}` and `{y}`: the app's own map images, or any provider's. */
139
+ url: string;
140
+ darkUrl?: string;
141
+ satelliteUrl?: string;
142
+ credit: Credit | Credit[];
143
+ maxZoom?: number;
144
+ tileSize?: number;
145
+ zoomOffset?: number;
146
+ search?: AddressSearch;
147
+ reverse?: ReverseSearch;
148
+ searchAsYouType?: boolean;
149
+ }
150
+ /** Map images from any address, such as the app's own server, with their credit. */
151
+ export declare function tiles(options: TilesOptions): MapProvider;
152
+ export {};