@fieldia/map 0.18.0 → 0.19.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 (146) hide show
  1. package/README.md +143 -3
  2. package/package.json +4 -4
  3. package/src/index.d.mts +5 -0
  4. package/src/index.d.ts +5 -0
  5. package/src/index.js +4 -1
  6. package/src/index.js.map +1 -1
  7. package/src/index.mjs +2 -0
  8. package/src/index.mjs.map +1 -1
  9. package/src/lib/address-labels.d.mts +33 -0
  10. package/src/lib/address-labels.d.ts +33 -0
  11. package/src/lib/address-labels.js +16 -0
  12. package/src/lib/address-labels.js.map +1 -0
  13. package/src/lib/address-labels.mjs +12 -0
  14. package/src/lib/address-labels.mjs.map +1 -0
  15. package/src/lib/address-line.d.mts +11 -0
  16. package/src/lib/address-line.d.ts +11 -0
  17. package/src/lib/address-line.js +51 -0
  18. package/src/lib/address-line.js.map +1 -0
  19. package/src/lib/address-line.mjs +47 -0
  20. package/src/lib/address-line.mjs.map +1 -0
  21. package/src/lib/address-names.d.mts +38 -0
  22. package/src/lib/address-names.d.ts +38 -0
  23. package/src/lib/address-names.js +240 -0
  24. package/src/lib/address-names.js.map +1 -0
  25. package/src/lib/address-names.mjs +232 -0
  26. package/src/lib/address-names.mjs.map +1 -0
  27. package/src/lib/address-parts.d.mts +146 -0
  28. package/src/lib/address-parts.d.ts +146 -0
  29. package/src/lib/address-parts.js +866 -0
  30. package/src/lib/address-parts.js.map +1 -0
  31. package/src/lib/address-parts.mjs +851 -0
  32. package/src/lib/address-parts.mjs.map +1 -0
  33. package/src/lib/address-search.d.mts +25 -0
  34. package/src/lib/address-search.d.ts +25 -0
  35. package/src/lib/address-search.js +70 -0
  36. package/src/lib/address-search.js.map +1 -0
  37. package/src/lib/address-search.mjs +67 -0
  38. package/src/lib/address-search.mjs.map +1 -0
  39. package/src/lib/address-suggest.d.mts +21 -0
  40. package/src/lib/address-suggest.d.ts +21 -0
  41. package/src/lib/address-suggest.js +273 -0
  42. package/src/lib/address-suggest.js.map +1 -0
  43. package/src/lib/address-suggest.mjs +270 -0
  44. package/src/lib/address-suggest.mjs.map +1 -0
  45. package/src/lib/area-count.d.mts +47 -0
  46. package/src/lib/area-count.d.ts +47 -0
  47. package/src/lib/area-count.js +123 -0
  48. package/src/lib/area-count.js.map +1 -0
  49. package/src/lib/area-count.mjs +116 -0
  50. package/src/lib/area-count.mjs.map +1 -0
  51. package/src/lib/card.d.mts +14 -5
  52. package/src/lib/card.d.ts +14 -5
  53. package/src/lib/card.js +67 -12
  54. package/src/lib/card.js.map +1 -1
  55. package/src/lib/card.mjs +66 -12
  56. package/src/lib/card.mjs.map +1 -1
  57. package/src/lib/embed.d.mts +86 -0
  58. package/src/lib/embed.d.ts +86 -0
  59. package/src/lib/embed.js +96 -0
  60. package/src/lib/embed.js.map +1 -0
  61. package/src/lib/embed.mjs +93 -0
  62. package/src/lib/embed.mjs.map +1 -0
  63. package/src/lib/form-map.js +9 -7
  64. package/src/lib/form-map.js.map +1 -1
  65. package/src/lib/form-map.mjs +10 -8
  66. package/src/lib/form-map.mjs.map +1 -1
  67. package/src/lib/kinds.d.mts +6 -4
  68. package/src/lib/kinds.d.ts +6 -4
  69. package/src/lib/kinds.js +49 -2
  70. package/src/lib/kinds.js.map +1 -1
  71. package/src/lib/kinds.mjs +49 -2
  72. package/src/lib/kinds.mjs.map +1 -1
  73. package/src/lib/labels.d.mts +2 -0
  74. package/src/lib/labels.d.ts +2 -0
  75. package/src/lib/labels.js +4 -0
  76. package/src/lib/labels.js.map +1 -1
  77. package/src/lib/labels.mjs +4 -0
  78. package/src/lib/labels.mjs.map +1 -1
  79. package/src/lib/list-view.d.mts +37 -1
  80. package/src/lib/list-view.d.ts +37 -1
  81. package/src/lib/list-view.js +97 -37
  82. package/src/lib/list-view.js.map +1 -1
  83. package/src/lib/list-view.mjs +97 -38
  84. package/src/lib/list-view.mjs.map +1 -1
  85. package/src/lib/map-core.d.mts +6 -1
  86. package/src/lib/map-core.d.ts +6 -1
  87. package/src/lib/map-core.js +13 -5
  88. package/src/lib/map-core.js.map +1 -1
  89. package/src/lib/map-core.mjs +13 -5
  90. package/src/lib/map-core.mjs.map +1 -1
  91. package/src/lib/pins.d.mts +20 -8
  92. package/src/lib/pins.d.ts +20 -8
  93. package/src/lib/pins.js +60 -15
  94. package/src/lib/pins.js.map +1 -1
  95. package/src/lib/pins.mjs +60 -17
  96. package/src/lib/pins.mjs.map +1 -1
  97. package/src/lib/place.js +23 -11
  98. package/src/lib/place.js.map +1 -1
  99. package/src/lib/place.mjs +23 -11
  100. package/src/lib/place.mjs.map +1 -1
  101. package/src/lib/providers.d.mts +16 -0
  102. package/src/lib/providers.d.ts +16 -0
  103. package/src/lib/providers.js +71 -112
  104. package/src/lib/providers.js.map +1 -1
  105. package/src/lib/providers.mjs +71 -112
  106. package/src/lib/providers.mjs.map +1 -1
  107. package/src/lib/regions.js +18 -1
  108. package/src/lib/regions.js.map +1 -1
  109. package/src/lib/regions.mjs +18 -1
  110. package/src/lib/regions.mjs.map +1 -1
  111. package/src/lib/route-line.d.mts +9 -0
  112. package/src/lib/route-line.d.ts +9 -0
  113. package/src/lib/route-line.js +13 -0
  114. package/src/lib/route-line.js.map +1 -1
  115. package/src/lib/route-line.mjs +11 -0
  116. package/src/lib/route-line.mjs.map +1 -1
  117. package/src/lib/routes.js +6 -2
  118. package/src/lib/routes.js.map +1 -1
  119. package/src/lib/routes.mjs +6 -2
  120. package/src/lib/routes.mjs.map +1 -1
  121. package/src/lib/search-box.d.mts +20 -2
  122. package/src/lib/search-box.d.ts +20 -2
  123. package/src/lib/search-box.js +133 -44
  124. package/src/lib/search-box.js.map +1 -1
  125. package/src/lib/search-box.mjs +133 -44
  126. package/src/lib/search-box.mjs.map +1 -1
  127. package/src/lib/settings.d.mts +19 -2
  128. package/src/lib/settings.d.ts +19 -2
  129. package/src/lib/styles.d.mts +12 -1
  130. package/src/lib/styles.d.ts +12 -1
  131. package/src/lib/styles.js +61 -3
  132. package/src/lib/styles.js.map +1 -1
  133. package/src/lib/styles.mjs +59 -2
  134. package/src/lib/styles.mjs.map +1 -1
  135. package/src/lib/view-box.d.mts +18 -0
  136. package/src/lib/view-box.d.ts +18 -0
  137. package/src/lib/view-box.js +31 -0
  138. package/src/lib/view-box.js.map +1 -0
  139. package/src/lib/view-box.mjs +25 -0
  140. package/src/lib/view-box.mjs.map +1 -0
  141. package/src/lib/widgets.d.mts +3 -0
  142. package/src/lib/widgets.d.ts +3 -0
  143. package/src/lib/widgets.js +10 -1
  144. package/src/lib/widgets.js.map +1 -1
  145. package/src/lib/widgets.mjs +10 -1
  146. package/src/lib/widgets.mjs.map +1 -1
package/README.md CHANGED
@@ -108,6 +108,59 @@ styles or its words.
108
108
  A card offers the list's own buttons too, each pressed for its record alone
109
109
  ("Assign", for this driver).
110
110
 
111
+ How the map sits in its page: `height` is pixels, or `fill` (as tall as the
112
+ element it is put in), as tall as the window allows (320 to 640 pixels) unless
113
+ said; `gestures: "all"` lets the map take every gesture — one finger pans, the
114
+ wheel zooms with no key held — where it is most of its page (unless said, one
115
+ finger and the wheel scroll the page past it); `fitZoom` is the closest it comes
116
+ when it fits its records, 16 unless said.
117
+
118
+ Once the map is moved, "Search this area" says how many records the view holds,
119
+ "Search this area (24)", when the records on hand can tell (all the search
120
+ finds, and a view within any area already searched). Otherwise, with
121
+ `countArea: true` in the settings, the data source is asked: one record, its
122
+ `total` the count, a moment after the map stops, the request's `signal` aborted
123
+ when it moves again; or `countArea` is the app's own
124
+ `(filter, signal) => Promise<number>`. Each time it stops, the map's element
125
+ sends `fd-map-view` (it bubbles): `{ center, zoom, bounds, byPerson }`.
126
+
127
+ ## A list's map in a page of your own
128
+
129
+ A page that is not Fieldia's — its own list, filters and address — shows a list's
130
+ map beside them with `mountListMap`. The app gives the page that describes the
131
+ records (a list with `map`), a data source or the records themselves, the
132
+ conditions they are found by, and what to do when the map asks for something; it
133
+ gets back the map.
134
+
135
+ ```ts
136
+ import { mountListMap, azureMaps } from '@fieldia/map';
137
+
138
+ const map = mountListMap(element, {
139
+ page, // a list page with "map"
140
+ provider: azureMaps({ key }),
141
+ dataSource, // or records: [{ id, values }, …]
142
+ filter: () => yourSearch(), // the conditions the records are found by
143
+ start: { center: { lat: 30.05, lng: 31.23 }, zoom: 13 }, // from the address: no fit at first
144
+ countArea: true,
145
+ onSearch: ({ kind, filter }) => { keep(kind, filter); map.reload(); }, // 'view', 'drawn' or 'region'
146
+ onViewChange: ({ center, zoom, bounds, byPerson }) => writeTheAddress(center, zoom),
147
+ onHighlight: (id) => lightYourRow(id),
148
+ onOpenRecord: (id) => location.assign(`/homes/${id}`),
149
+ });
150
+ map.highlight(id); // a row of yours under the pointer
151
+ map.reload(); // your search changed
152
+ map.destroy();
153
+ ```
154
+
155
+ Also `locale` (a tag; the document's language unless said), `sort`, `icons`,
156
+ `isChosen` and `onChoose`, `actions` and `onAction`, `onSort` (Nearest first),
157
+ and every setting `mapListViews` takes. Without `onSearch` the map offers no
158
+ search. It brings its own base on its own element alone (a part hidden stays
159
+ hidden, words for a screen reader, its buttons) and Fieldia's colours as tokens,
160
+ light or dark by the page's `color-scheme`: set your own on `.fd-map-embed`
161
+ (`.fd-map-embed { --fd-accent: #375dfb; }`), and your rule wins whatever its
162
+ weight.
163
+
111
164
  ## A map on a form
112
165
 
113
166
  A part of type `map` shows the record's places as layers: the record's own
@@ -199,7 +252,7 @@ pin, or the bubble, that holds the place they were on.
199
252
  | Provider | Road | Dark | Satellite | Traffic | Address search | Routes | Reachable area |
200
253
  | --- | --- | --- | --- | --- | --- | --- | --- |
201
254
  | `azureMaps({ key })` or `({ token, clientId })` | yes | yes | yes | yes, from zoom 6, in dark colours on the dark map, drawn again every four minutes | yes, as people type | car, foot | car |
202
- | `googleMaps({ key, region, logo })` (Map Tiles API) | yes | no | yes | yes, its traffic layer | Places API, as people type | car, bike, foot (Routes API) | no |
255
+ | `googleMaps({ key, region, logo })` (Map Tiles API) | yes | no | yes | yes, its traffic layer | Places API, as people type | car (with traffic), foot; bike where Google has bicycle routes, none in Egypt, Saudi Arabia, the UAE or Jordan (Routes API) | no: Google's Isochrones API is in preview, and Fieldia does not use it yet |
203
256
  | `mapbox({ token, trafficStyle })` | yes | yes | yes | from `trafficStyle`, a style of yours with Mapbox Traffic's lines alone | yes, as people type | car (traffic), bike, foot | car, bike, foot |
204
257
  | `tiles({ url, credit, trafficUrl, route, reach })` | the app's own map images | | | the app's own (`trafficUrl`) | the app's own | the app's own | the app's own |
205
258
  | `openStreetMap()` | yes, **for demos only** | no | no | no | Photon, as people type, nearest first (or `{ search: 'nominatim' }`, on Enter) | OSRM's demo server, car only (or `osrmUrl`) | no |
@@ -214,11 +267,98 @@ treat an app in use as heavy use. Photon can run on your own server
214
267
  (`openStreetMap({ photonUrl })`).
215
268
 
216
269
  Suggestions come as people type where the provider allows it, nearest where the
217
- map is looking first, each on two lines (the place, then where it is); Enter
218
- takes the first. "My location" says how sure it is: a rough location (a
270
+ map is looking first (a map of the whole world, opened with no centre, looks
271
+ nowhere), each on two lines (the place, then where it is); Enter takes the one
272
+ marked with the arrows (Down marks the first, Up the last, each going round at
273
+ the end), or the first of a list made for the words in the box:
274
+ words typed after the list came are searched for at once, and nothing is
275
+ picked from the list before them. "My location" says how sure it is: a rough location (a
219
276
  desktop's, placed by its network) shows the circle it may be anywhere in, says
220
277
  how wide, and names no address from it.
221
278
 
279
+ An address with suggestions (`address-search` on a char field) keeps them to
280
+ the `countries` the page names (ISO codes; "UK" is read as "GB", a code no one
281
+ knows is left out and said in the console). Azure Maps is asked once for each
282
+ country, up to ten (an autocomplete request is a tenth of a Search
283
+ transaction); Google, for fifteen at most; Mapbox and Nominatim, for the list;
284
+ Photon's answers are kept to them. Nearest `near` first (or where the app's
285
+ maps open), so give a point in the page's own country: Azure ranks another
286
+ country's suggestions by their distance from it. Addresses come before shops
287
+ and malls where the provider says which are which (Google, Azure), and an
288
+ address field asks Azure for no postcodes alone, and the word for a district
289
+ typed before its name ("حي الروضة") is left out of the words it is asked, as
290
+ Azure names its districts without it. A suggestion of Azure's is located when
291
+ picked, asked of Azure's geocoding by its own address in its structured form
292
+ (its street, its district for the locality where it names one, then its
293
+ locality, its governorate or province, postcode and country), and only
294
+ there: a district named alike in another town is never taken for it, as no
295
+ hit outside its own admin districts is. A street is placed in its own
296
+ district: the stretch that says it is there, else one in the district's box
297
+ as Azure has it (a road with a name a little beyond it, as it runs on into
298
+ the next); never a street of the name in another district ("Kamel El
299
+ Shenawy" in Garden City, not New Cairo's), and for a street named by its
300
+ number alone ("30 Street", "شارع 6") never another district's of that number.
301
+ Its city is read from them each country's way (in Egypt the governorate's
302
+ city where the governorate is one, Zamalek is Cairo's, and the town
303
+ elsewhere, Mansoura in Dakahlia; in Saudi Arabia the governorate's city; in
304
+ the emirate of Abu Dhabi, the city it is in); a suggestion that names no
305
+ region ("البرشاء 2") takes its city and region from the place found, and one
306
+ that says less of a place listed beside it is left out. A region or a city
307
+ of Egypt, Saudi Arabia, the UAE or Jordan is named one way in each language,
308
+ whichever of its names or codes Azure gives ("Sharjah Emirate", "Ash
309
+ Shāriqah" and "SH" are Sharjah; "Ţanţā" and "طنطا" are Tanta), and once in a
310
+ line ("Giza", never "Giza, Al Jizah"); a district Azure names only in its own
311
+ line is said too ("30 Street, Al Fisht, Sharjah"), and named so where it is
312
+ a road's with no name of its own ("Abu Tina", never Azure's French
313
+ "Charjah"). It is said to be only near (`precise: false`) when Azure is
314
+ unsure of it, or finds only the street for a house, the district for a
315
+ street (its own, before its town), the town for a district; found nowhere in
316
+ its own districts, no place is written (the field says so under the box),
317
+ and its parts still are. A search still waiting when
318
+ a suggestion is picked or the box is left is dropped, and Enter never searches
319
+ for the address a pick wrote. The place and parts a pick wrote stay while the
320
+ words are only edited (a flat added, a word taken out); once the box is left
321
+ emptied, or with the address picked typed over (all of it selected, then typed
322
+ or pasted), they go with it.
323
+
324
+ Azure's and Google's suggestions, places and parts were checked against their
325
+ live services in October 2026, in English and Arabic, across Egypt, Saudi
326
+ Arabia, the UAE and Jordan. Mapbox's are read as its documentation describes
327
+ them and have not yet been checked against its live service.
328
+
329
+ Escape drops a search waiting or on its way, as more typing, a pick and
330
+ leaving the box do, and no search is said to be going once it is dropped; a
331
+ list closed takes what was said of it with it. A search waiting is never
332
+ sent; one on its way is not called back, as the provider has it and may bill
333
+ it, but its answer opens nothing. While one address is typed, words asked for
334
+ once (near the same place) show what they brought again, however they come
335
+ back (a letter taken back, Enter after Escape), and words still on their way,
336
+ though dropped, are waited for, not asked again; after a pick they are a new
337
+ address's, asked for anew, and what is still on its way is called back. A
338
+ pick that finds no place, or no parts, takes back the ones the pick before it
339
+ wrote (another address's), never a place set by hand since, as emptying the
340
+ box and leaving it does (with other words typed in their place or none);
341
+ words only edited keep them. One found only near the address (`precise:
342
+ false`) is written, and the field says so under the box; one whose place the
343
+ map did not answer for (a line dropped, the provider down) says that, not
344
+ that it is not on the map. Google writes the UAE's addresses with dashes
345
+ between their pieces ("Sheikh Zayed Rd - Dubai - United Arab Emirates"): they
346
+ are read as its commas elsewhere, each piece said once, a landmark's name too,
347
+ and a suggestion's name not again on the line under it.
348
+
349
+ Google's costs, as its pricing pages put them (October 2026): a session of
350
+ suggestions ended by a pick bills its first 12 requests (Autocomplete
351
+ Requests) and the place's details (Place Details Essentials: its place, its
352
+ line and its parts, `location,formattedAddress,addressComponents`, are all
353
+ three that SKU's fields, asked for whatever the page keeps, as the parts name
354
+ the country the line is written with; the place's name, `displayName`, would
355
+ make it Pro, and the suggestion gives it); a session
356
+ never picked bills each request. A session's token goes with its first Place
357
+ Details alone: Google bills a token used again as no session. A route by car
358
+ asks for traffic, which makes it Compute Routes Pro; on foot (or by bike) with
359
+ up to 10 stops it is Essentials, 11 to 25 stops Pro, and Google refuses more
360
+ than 25.
361
+
222
362
  Pass your own `search` (and `reverse`) to `mapWidgets` to use your own address
223
363
  search with any provider.
224
364
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fieldia/map",
3
- "version": "0.18.0",
3
+ "version": "0.19.1",
4
4
  "description": "Fieldia's maps: a place and an area as fields, and a list's records on a map, on any map provider. Leaflet, loaded only where a map is shown.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://fieldia.dev",
@@ -21,9 +21,9 @@
21
21
  "./package.json": "./package.json"
22
22
  },
23
23
  "dependencies": {
24
- "@fieldia/core": "0.18.0",
25
- "@fieldia/viewer": "0.18.0",
26
- "@fieldia/widgets": "0.18.0",
24
+ "@fieldia/core": "0.19.1",
25
+ "@fieldia/viewer": "0.19.1",
26
+ "@fieldia/widgets": "0.19.1",
27
27
  "leaflet": "^1.9.4",
28
28
  "tslib": "^2.8.1"
29
29
  },
package/src/index.d.mts CHANGED
@@ -8,3 +8,8 @@ export type { MapSettings } from './lib/settings.mjs';
8
8
  export { azureMaps, googleMaps, mapbox, openStreetMap, tiles, type AddressSearch, type AzureMapsOptions, type BaseMap, type Credit, type GoogleMapsOptions, type MapboxOptions, type MapProvider, type MapView, type OpenStreetMapOptions, type PlaceFound, type ReachFinder, type ReachFound, type ReachRequest, type ReverseSearch, type RouteFinder, type RouteFound, type RouteRequest, type TravelMode, type SearchRequest, type TileSpec, type TilesOptions, } from './lib/providers.mjs';
9
9
  export { readArea, readPoint, writeArea, writePoint, metresBetween, type Area, type AreaFeature, type LatLng, type PointGeometry, type Shape } from './lib/geo.mjs';
10
10
  export { MAP_LABELS, type MapLabels } from './lib/labels.mjs';
11
+ export type { AddressLabels } from './lib/address-labels.mjs';
12
+ export type { AddressParts } from './lib/address-parts.mjs';
13
+ export { mountListMap, type ListMapHandle, type ListMapOptions } from './lib/embed.mjs';
14
+ export type { MapSearch, MapViewChange } from './lib/list-view.mjs';
15
+ export type { Box as MapBounds } from './lib/view-box.mjs';
package/src/index.d.ts CHANGED
@@ -8,3 +8,8 @@ export type { MapSettings } from './lib/settings';
8
8
  export { azureMaps, googleMaps, mapbox, openStreetMap, tiles, type AddressSearch, type AzureMapsOptions, type BaseMap, type Credit, type GoogleMapsOptions, type MapboxOptions, type MapProvider, type MapView, type OpenStreetMapOptions, type PlaceFound, type ReachFinder, type ReachFound, type ReachRequest, type ReverseSearch, type RouteFinder, type RouteFound, type RouteRequest, type TravelMode, type SearchRequest, type TileSpec, type TilesOptions, } from './lib/providers';
9
9
  export { readArea, readPoint, writeArea, writePoint, metresBetween, type Area, type AreaFeature, type LatLng, type PointGeometry, type Shape } from './lib/geo';
10
10
  export { MAP_LABELS, type MapLabels } from './lib/labels';
11
+ export type { AddressLabels } from './lib/address-labels';
12
+ export type { AddressParts } from './lib/address-parts';
13
+ export { mountListMap, type ListMapHandle, type ListMapOptions } from './lib/embed';
14
+ export type { MapSearch, MapViewChange } from './lib/list-view';
15
+ export type { Box as MapBounds } from './lib/view-box';
package/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MAP_LABELS = exports.metresBetween = exports.writePoint = exports.writeArea = exports.readPoint = exports.readArea = exports.tiles = exports.openStreetMap = exports.mapbox = exports.googleMaps = exports.azureMaps = exports.mapKinds = exports.MAP_ICONS = exports.mapParts = exports.mapListViews = exports.mapWidgets = void 0;
3
+ exports.mountListMap = exports.MAP_LABELS = exports.metresBetween = exports.writePoint = exports.writeArea = exports.readPoint = exports.readArea = exports.tiles = exports.openStreetMap = exports.mapbox = exports.googleMaps = exports.azureMaps = exports.mapKinds = exports.MAP_ICONS = exports.mapParts = exports.mapListViews = exports.mapWidgets = void 0;
4
4
  var widgets_1 = require("./lib/widgets");
5
5
  Object.defineProperty(exports, "mapWidgets", { enumerable: true, get: function () { return widgets_1.mapWidgets; } });
6
6
  var list_view_1 = require("./lib/list-view");
@@ -25,4 +25,7 @@ Object.defineProperty(exports, "writePoint", { enumerable: true, get: function (
25
25
  Object.defineProperty(exports, "metresBetween", { enumerable: true, get: function () { return geo_1.metresBetween; } });
26
26
  var labels_1 = require("./lib/labels");
27
27
  Object.defineProperty(exports, "MAP_LABELS", { enumerable: true, get: function () { return labels_1.MAP_LABELS; } });
28
+ // A list's map in a page of the app's own, outside the viewer.
29
+ var embed_1 = require("./lib/embed");
30
+ Object.defineProperty(exports, "mountListMap", { enumerable: true, get: function () { return embed_1.mountListMap; } });
28
31
  //# sourceMappingURL=index.js.map
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/map/src/index.ts"],"names":[],"mappings":";;;AAAA,yCAA2C;AAAlC,qGAAA,UAAU,OAAA;AACnB,6CAA+C;AAAtC,yGAAA,YAAY,OAAA;AACrB,2CAA0C;AAAjC,oGAAA,QAAQ,OAAA;AACjB,6CAA4C;AAAnC,sGAAA,SAAS,OAAA;AAElB,qCAA0E;AAAjE,iGAAA,QAAQ,OAAA;AAEjB,6CA2ByB;AA1BvB,sGAAA,SAAS,OAAA;AACT,uGAAA,UAAU,OAAA;AACV,mGAAA,MAAM,OAAA;AACN,0GAAA,aAAa,OAAA;AACb,kGAAA,KAAK,OAAA;AAuBP,iCAAgK;AAAvJ,+FAAA,QAAQ,OAAA;AAAE,gGAAA,SAAS,OAAA;AAAE,gGAAA,SAAS,OAAA;AAAE,iGAAA,UAAU,OAAA;AAAE,oGAAA,aAAa,OAAA;AAClE,uCAA0D;AAAjD,oGAAA,UAAU,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/map/src/index.ts"],"names":[],"mappings":";;;AAAA,yCAA2C;AAAlC,qGAAA,UAAU,OAAA;AACnB,6CAA+C;AAAtC,yGAAA,YAAY,OAAA;AACrB,2CAA0C;AAAjC,oGAAA,QAAQ,OAAA;AACjB,6CAA4C;AAAnC,sGAAA,SAAS,OAAA;AAElB,qCAA0E;AAAjE,iGAAA,QAAQ,OAAA;AAEjB,6CA2ByB;AA1BvB,sGAAA,SAAS,OAAA;AACT,uGAAA,UAAU,OAAA;AACV,mGAAA,MAAM,OAAA;AACN,0GAAA,aAAa,OAAA;AACb,kGAAA,KAAK,OAAA;AAuBP,iCAAgK;AAAvJ,+FAAA,QAAQ,OAAA;AAAE,gGAAA,SAAS,OAAA;AAAE,gGAAA,SAAS,OAAA;AAAE,iGAAA,UAAU,OAAA;AAAE,oGAAA,aAAa,OAAA;AAClE,uCAA0D;AAAjD,oGAAA,UAAU,OAAA;AAGnB,+DAA+D;AAC/D,qCAAoF;AAA3E,qGAAA,YAAY,OAAA"}
package/src/index.mjs CHANGED
@@ -6,4 +6,6 @@ export { mapKinds } from './lib/kinds.mjs';
6
6
  export { azureMaps, googleMaps, mapbox, openStreetMap, tiles, } from './lib/providers.mjs';
7
7
  export { readArea, readPoint, writeArea, writePoint, metresBetween } from './lib/geo.mjs';
8
8
  export { MAP_LABELS } from './lib/labels.mjs';
9
+ // A list's map in a page of the app's own, outside the viewer.
10
+ export { mountListMap } from './lib/embed.mjs';
9
11
  //# sourceMappingURL=index.mjs.map
package/src/index.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../../../libs/map/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAqC,MAAM,aAAa,CAAC;AAE1E,OAAO,EACL,SAAS,EACT,UAAU,EACV,MAAM,EACN,aAAa,EACb,KAAK,GAsBN,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAA4E,MAAM,WAAW,CAAC;AAChK,OAAO,EAAE,UAAU,EAAkB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../../../libs/map/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAqC,MAAM,aAAa,CAAC;AAE1E,OAAO,EACL,SAAS,EACT,UAAU,EACV,MAAM,EACN,aAAa,EACb,KAAK,GAsBN,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAA4E,MAAM,WAAW,CAAC;AAChK,OAAO,EAAE,UAAU,EAAkB,MAAM,cAAc,CAAC;AAG1D,+DAA+D;AAC/D,OAAO,EAAE,YAAY,EAA2C,MAAM,aAAa,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { Locale } from '@fieldia/core';
2
+ import { type MapLabels } from './labels.mjs';
3
+ /**
4
+ * The words of an address field that suggests addresses
5
+ * (`char.address-search`), and of its kind in the designer: in a module of
6
+ * their own, so a page that shows forms (and no designer) loads them with
7
+ * the field's suggestions, not before.
8
+ */
9
+ export interface AddressLabels {
10
+ /** Said to screen readers as suggestions come: `{n}` how many. */
11
+ suggested: string;
12
+ /**
13
+ * Shown under the box when the address picked is not found on the map, and
14
+ * no place is written for it; when it is placed only near it (`precise:
15
+ * false`); when its place could not be asked for, the map not answering (a
16
+ * line dropped). Their words come with the suggestions.
17
+ */
18
+ notPlaced: string;
19
+ placedNear: string;
20
+ locateFailed: string;
21
+ addressKind: string;
22
+ /** The designer's settings: the field a picked address's place goes into, the field its parts go into, the country it keeps to. */
23
+ settingPlace: string;
24
+ settingParts: string;
25
+ settingCountry: string;
26
+ anywhere: string;
27
+ }
28
+ /** The words said under the box, which come with the suggestions' code (address-suggest.ts). */
29
+ type SaidAfterAPick = 'notPlaced' | 'placedNear' | 'locateFailed';
30
+ export declare const ADDRESS_LABELS: Record<Locale, Omit<AddressLabels, SaidAfterAPick>>;
31
+ /** An address field's words for a page's language, the maps' own with them, and the app's own over both. */
32
+ export declare function addressLabels(locale: Locale | undefined, own?: Partial<MapLabels & AddressLabels>): MapLabels & Omit<AddressLabels, SaidAfterAPick> & Partial<AddressLabels>;
33
+ export {};
@@ -0,0 +1,33 @@
1
+ import type { Locale } from '@fieldia/core';
2
+ import { type MapLabels } from './labels';
3
+ /**
4
+ * The words of an address field that suggests addresses
5
+ * (`char.address-search`), and of its kind in the designer: in a module of
6
+ * their own, so a page that shows forms (and no designer) loads them with
7
+ * the field's suggestions, not before.
8
+ */
9
+ export interface AddressLabels {
10
+ /** Said to screen readers as suggestions come: `{n}` how many. */
11
+ suggested: string;
12
+ /**
13
+ * Shown under the box when the address picked is not found on the map, and
14
+ * no place is written for it; when it is placed only near it (`precise:
15
+ * false`); when its place could not be asked for, the map not answering (a
16
+ * line dropped). Their words come with the suggestions.
17
+ */
18
+ notPlaced: string;
19
+ placedNear: string;
20
+ locateFailed: string;
21
+ addressKind: string;
22
+ /** The designer's settings: the field a picked address's place goes into, the field its parts go into, the country it keeps to. */
23
+ settingPlace: string;
24
+ settingParts: string;
25
+ settingCountry: string;
26
+ anywhere: string;
27
+ }
28
+ /** The words said under the box, which come with the suggestions' code (address-suggest.ts). */
29
+ type SaidAfterAPick = 'notPlaced' | 'placedNear' | 'locateFailed';
30
+ export declare const ADDRESS_LABELS: Record<Locale, Omit<AddressLabels, SaidAfterAPick>>;
31
+ /** An address field's words for a page's language, the maps' own with them, and the app's own over both. */
32
+ export declare function addressLabels(locale: Locale | undefined, own?: Partial<MapLabels & AddressLabels>): MapLabels & Omit<AddressLabels, SaidAfterAPick> & Partial<AddressLabels>;
33
+ export {};
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ADDRESS_LABELS = void 0;
4
+ exports.addressLabels = addressLabels;
5
+ const labels_1 = require("./labels");
6
+ exports.ADDRESS_LABELS = {
7
+ en: { suggested: 'Suggestions: {n}', addressKind: 'Address search', settingPlace: 'Place goes into', settingParts: 'Parts go into', settingCountry: 'Addresses in', anywhere: 'Any country' },
8
+ ar: { suggested: 'الاقتراحات: {n}', addressKind: 'بحث عن عنوان', settingPlace: 'يُكتب المكان في', settingParts: 'تُكتب أجزاؤه في', settingCountry: 'العناوين في', anywhere: 'أي بلد' },
9
+ fr: { suggested: 'Suggestions : {n}', addressKind: 'Recherche d’adresse', settingPlace: 'Le lieu va dans', settingParts: 'Ses parties vont dans', settingCountry: 'Pays des adresses', anywhere: 'Tous les pays' },
10
+ de: { suggested: 'Vorschläge: {n}', addressKind: 'Adresssuche', settingPlace: 'Ort kommt in', settingParts: 'Teile kommen in', settingCountry: 'Land der Adressen', anywhere: 'Alle Länder' },
11
+ };
12
+ /** An address field's words for a page's language, the maps' own with them, and the app's own over both. */
13
+ function addressLabels(locale, own) {
14
+ return { ...labels_1.MAP_LABELS[locale ?? 'en'], ...exports.ADDRESS_LABELS[locale ?? 'en'], ...own };
15
+ }
16
+ //# sourceMappingURL=address-labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address-labels.js","sourceRoot":"","sources":["../../../../../libs/map/src/lib/address-labels.ts"],"names":[],"mappings":";;;AAwCA,sCAEC;AAzCD,qCAAsD;AA+BzC,QAAA,cAAc,GAAwD;IACjF,EAAE,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE;IAC7L,EAAE,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE;IACtL,EAAE,EAAE,EAAE,SAAS,EAAE,mBAAmB,EAAE,WAAW,EAAE,qBAAqB,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,uBAAuB,EAAE,cAAc,EAAE,mBAAmB,EAAE,QAAQ,EAAE,eAAe,EAAE;IAClN,EAAE,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,mBAAmB,EAAE,QAAQ,EAAE,aAAa,EAAE;CAC9L,CAAC;AAEF,4GAA4G;AAC5G,SAAgB,aAAa,CAAC,MAA0B,EAAE,GAAwC;IAChG,OAAO,EAAE,GAAG,mBAAU,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,GAAG,sBAAc,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC;AACtF,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { MAP_LABELS } from './labels.mjs';
2
+ export const ADDRESS_LABELS = {
3
+ en: { suggested: 'Suggestions: {n}', addressKind: 'Address search', settingPlace: 'Place goes into', settingParts: 'Parts go into', settingCountry: 'Addresses in', anywhere: 'Any country' },
4
+ ar: { suggested: 'الاقتراحات: {n}', addressKind: 'بحث عن عنوان', settingPlace: 'يُكتب المكان في', settingParts: 'تُكتب أجزاؤه في', settingCountry: 'العناوين في', anywhere: 'أي بلد' },
5
+ fr: { suggested: 'Suggestions : {n}', addressKind: 'Recherche d’adresse', settingPlace: 'Le lieu va dans', settingParts: 'Ses parties vont dans', settingCountry: 'Pays des adresses', anywhere: 'Tous les pays' },
6
+ de: { suggested: 'Vorschläge: {n}', addressKind: 'Adresssuche', settingPlace: 'Ort kommt in', settingParts: 'Teile kommen in', settingCountry: 'Land der Adressen', anywhere: 'Alle Länder' },
7
+ };
8
+ /** An address field's words for a page's language, the maps' own with them, and the app's own over both. */
9
+ export function addressLabels(locale, own) {
10
+ return { ...MAP_LABELS[locale ?? 'en'], ...ADDRESS_LABELS[locale ?? 'en'], ...own };
11
+ }
12
+ //# sourceMappingURL=address-labels.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address-labels.mjs","sourceRoot":"","sources":["../../../../../libs/map/src/lib/address-labels.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAkB,MAAM,UAAU,CAAC;AA+BtD,MAAM,CAAC,MAAM,cAAc,GAAwD;IACjF,EAAE,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE;IAC7L,EAAE,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE;IACtL,EAAE,EAAE,EAAE,SAAS,EAAE,mBAAmB,EAAE,WAAW,EAAE,qBAAqB,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,uBAAuB,EAAE,cAAc,EAAE,mBAAmB,EAAE,QAAQ,EAAE,eAAe,EAAE;IAClN,EAAE,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,mBAAmB,EAAE,QAAQ,EAAE,aAAa,EAAE;CAC9L,CAAC;AAEF,4GAA4G;AAC5G,MAAM,UAAU,aAAa,CAAC,MAA0B,EAAE,GAAwC;IAChG,OAAO,EAAE,GAAG,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,GAAG,cAAc,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC;AACtF,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Locale } from '@fieldia/core';
2
+ /** `before`: what is said already, on a line above (a suggestion's name), and not said again. */
3
+ export declare function addressLine(pieces: unknown[], locale?: Locale, before?: unknown[]): string;
4
+ /**
5
+ * The direction most of a text's letters are written in, for a box or a
6
+ * line that shows an address in its own words: "rtl" for one mostly in
7
+ * Arabic, though it starts with a Latin street ("El Tahrir، الإسماعيلية،
8
+ * مصر"), "ltr" for one mostly in Latin on an Arabic page ("1 Mohammed
9
+ * Mahmoud"); "" when there are no letters, or as many each way: the page's.
10
+ */
11
+ export declare function directionOf(text: string): 'ltr' | 'rtl' | '';
@@ -0,0 +1,11 @@
1
+ import type { Locale } from '@fieldia/core';
2
+ /** `before`: what is said already, on a line above (a suggestion's name), and not said again. */
3
+ export declare function addressLine(pieces: unknown[], locale?: Locale, before?: unknown[]): string;
4
+ /**
5
+ * The direction most of a text's letters are written in, for a box or a
6
+ * line that shows an address in its own words: "rtl" for one mostly in
7
+ * Arabic, though it starts with a Latin street ("El Tahrir، الإسماعيلية،
8
+ * مصر"), "ltr" for one mostly in Latin on an Arabic page ("1 Mohammed
9
+ * Mahmoud"); "" when there are no letters, or as many each way: the page's.
10
+ */
11
+ export declare function directionOf(text: string): 'ltr' | 'rtl' | '';
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addressLine = addressLine;
4
+ exports.directionOf = directionOf;
5
+ /**
6
+ * An address on one line, as a field keeps it and a suggestion's second line
7
+ * shows it: its pieces in order (a name or a street, then where it is), each
8
+ * said once, joined as the page's language joins them, "، " in Arabic and
9
+ * ", " in the others. A piece is cut where a provider put its own commas, and
10
+ * left out when it repeats one said before it: the same words ("Cairo",
11
+ * "Cairo"), or a wider place named after it ("Cairo Governorate" after
12
+ * "Cairo", "محافظة القاهرة" after "القاهرة") unless it carries a number of
13
+ * its own, a postcode. A narrower piece holding a wider one's name, a street
14
+ * named after its city, stays: it was said first.
15
+ */
16
+ const MARKS = /[‎‏؜‪-‮⁦-⁩]/g;
17
+ /** A piece's words as compared: without the tatweel and the vowel marks Arabic may carry ("الشيـخ" is "الشيخ"). */
18
+ const words = (piece) => piece.replace(/\p{Mn}|\u0640/gu, '').toLowerCase().split(/\s+/);
19
+ /** Whether `few` are in `many`, one after another, as whole words. */
20
+ const within = (few, many) => many.some((_, at) => few.every((word, i) => many[at + i] === word));
21
+ /** Its pieces, cut where the provider put commas, without the marks it put in Arabic. */
22
+ const cut = (pieces) => pieces.flatMap((p) => (typeof p === 'string' ? p.replace(MARKS, '').split(/[,،]/) : [])).map((piece) => piece.trim()).filter(Boolean);
23
+ /** `before`: what is said already, on a line above (a suggestion's name), and not said again. */
24
+ function addressLine(pieces, locale, before = []) {
25
+ const said = cut(before).map(words);
26
+ const kept = [];
27
+ for (const text of cut(pieces)) {
28
+ const these = words(text);
29
+ if (said.some((earlier) => within(earlier, these) && (earlier.length === these.length || !/\p{Nd}/u.test(text))))
30
+ continue;
31
+ said.push(these);
32
+ kept.push(text);
33
+ }
34
+ return kept.join(locale === 'ar' ? '، ' : ', ');
35
+ }
36
+ /** Letters written right to left: Arabic's and Hebrew's. */
37
+ const RTL = /[\u0590-\u08FF\uFB1D-\uFDFF\uFE70-\uFEFF]/;
38
+ /**
39
+ * The direction most of a text's letters are written in, for a box or a
40
+ * line that shows an address in its own words: "rtl" for one mostly in
41
+ * Arabic, though it starts with a Latin street ("El Tahrir، الإسماعيلية،
42
+ * مصر"), "ltr" for one mostly in Latin on an Arabic page ("1 Mohammed
43
+ * Mahmoud"); "" when there are no letters, or as many each way: the page's.
44
+ */
45
+ function directionOf(text) {
46
+ const letters = text.match(/\p{L}/gu) ?? [];
47
+ const rtl = letters.filter((letter) => RTL.test(letter)).length;
48
+ const ltr = letters.length - rtl;
49
+ return rtl > ltr ? 'rtl' : ltr > rtl ? 'ltr' : '';
50
+ }
51
+ //# sourceMappingURL=address-line.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address-line.js","sourceRoot":"","sources":["../../../../../libs/map/src/lib/address-line.ts"],"names":[],"mappings":";;AAwBA,kCAUC;AAYD,kCAKC;AAjDD;;;;;;;;;;GAUG;AAEH,MAAM,KAAK,GAAG,cAAc,CAAC;AAC7B,mHAAmH;AACnH,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACjG,sEAAsE;AACtE,MAAM,MAAM,GAAG,CAAC,GAAa,EAAE,IAAc,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;AAEtH,yFAAyF;AACzF,MAAM,GAAG,GAAG,CAAC,MAAiB,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAEzK,iGAAiG;AACjG,SAAgB,WAAW,CAAC,MAAiB,EAAE,MAAe,EAAE,SAAoB,EAAE;IACpF,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,SAAS;QAC3H,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAClD,CAAC;AAED,4DAA4D;AAC5D,MAAM,GAAG,GAAG,2CAA2C,CAAC;AAExD;;;;;;GAMG;AACH,SAAgB,WAAW,CAAC,IAAY;IACtC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAC5C,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAChE,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC;IACjC,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACpD,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * An address on one line, as a field keeps it and a suggestion's second line
3
+ * shows it: its pieces in order (a name or a street, then where it is), each
4
+ * said once, joined as the page's language joins them, "، " in Arabic and
5
+ * ", " in the others. A piece is cut where a provider put its own commas, and
6
+ * left out when it repeats one said before it: the same words ("Cairo",
7
+ * "Cairo"), or a wider place named after it ("Cairo Governorate" after
8
+ * "Cairo", "محافظة القاهرة" after "القاهرة") unless it carries a number of
9
+ * its own, a postcode. A narrower piece holding a wider one's name, a street
10
+ * named after its city, stays: it was said first.
11
+ */
12
+ const MARKS = /[‎‏؜‪-‮⁦-⁩]/g;
13
+ /** A piece's words as compared: without the tatweel and the vowel marks Arabic may carry ("الشيـخ" is "الشيخ"). */
14
+ const words = (piece) => piece.replace(/\p{Mn}|\u0640/gu, '').toLowerCase().split(/\s+/);
15
+ /** Whether `few` are in `many`, one after another, as whole words. */
16
+ const within = (few, many) => many.some((_, at) => few.every((word, i) => many[at + i] === word));
17
+ /** Its pieces, cut where the provider put commas, without the marks it put in Arabic. */
18
+ const cut = (pieces) => pieces.flatMap((p) => (typeof p === 'string' ? p.replace(MARKS, '').split(/[,،]/) : [])).map((piece) => piece.trim()).filter(Boolean);
19
+ /** `before`: what is said already, on a line above (a suggestion's name), and not said again. */
20
+ export function addressLine(pieces, locale, before = []) {
21
+ const said = cut(before).map(words);
22
+ const kept = [];
23
+ for (const text of cut(pieces)) {
24
+ const these = words(text);
25
+ if (said.some((earlier) => within(earlier, these) && (earlier.length === these.length || !/\p{Nd}/u.test(text))))
26
+ continue;
27
+ said.push(these);
28
+ kept.push(text);
29
+ }
30
+ return kept.join(locale === 'ar' ? '، ' : ', ');
31
+ }
32
+ /** Letters written right to left: Arabic's and Hebrew's. */
33
+ const RTL = /[\u0590-\u08FF\uFB1D-\uFDFF\uFE70-\uFEFF]/;
34
+ /**
35
+ * The direction most of a text's letters are written in, for a box or a
36
+ * line that shows an address in its own words: "rtl" for one mostly in
37
+ * Arabic, though it starts with a Latin street ("El Tahrir، الإسماعيلية،
38
+ * مصر"), "ltr" for one mostly in Latin on an Arabic page ("1 Mohammed
39
+ * Mahmoud"); "" when there are no letters, or as many each way: the page's.
40
+ */
41
+ export function directionOf(text) {
42
+ const letters = text.match(/\p{L}/gu) ?? [];
43
+ const rtl = letters.filter((letter) => RTL.test(letter)).length;
44
+ const ltr = letters.length - rtl;
45
+ return rtl > ltr ? 'rtl' : ltr > rtl ? 'ltr' : '';
46
+ }
47
+ //# sourceMappingURL=address-line.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address-line.mjs","sourceRoot":"","sources":["../../../../../libs/map/src/lib/address-line.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AAEH,MAAM,KAAK,GAAG,cAAc,CAAC;AAC7B,mHAAmH;AACnH,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACjG,sEAAsE;AACtE,MAAM,MAAM,GAAG,CAAC,GAAa,EAAE,IAAc,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;AAEtH,yFAAyF;AACzF,MAAM,GAAG,GAAG,CAAC,MAAiB,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAEzK,iGAAiG;AACjG,MAAM,UAAU,WAAW,CAAC,MAAiB,EAAE,MAAe,EAAE,SAAoB,EAAE;IACpF,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,SAAS;QAC3H,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAClD,CAAC;AAED,4DAA4D;AAC5D,MAAM,GAAG,GAAG,2CAA2C,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAC5C,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAChE,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC;IACjC,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACpD,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { Locale } from '@fieldia/core';
2
+ /**
3
+ * What is known of the regions and cities of Egypt, Saudi Arabia, the UAE
4
+ * and Jordan, for reading Azure's addresses there, where each of its services
5
+ * names one place its own way: a region by its code ("RIY", "SH") or by a
6
+ * name ("Sharjah Emirate", "Ash Shāriqah", "منطقة الرياض", "مكة"), a city as
7
+ * a locality in another script ("Cairo" in an Arabic answer) or another
8
+ * spelling ("Ad Dammām", "الأسكندرية"). Each place here has one name in each
9
+ * language, which Fieldia writes, and every other name Azure was seen to give
10
+ * it (12–13 Oct 2026; each region's capital asked for in English and
11
+ * Arabic on 13 Oct). Loaded with the providers' address parts.
12
+ *
13
+ * A place is one of these only by its code or one of its names, the same
14
+ * words (without accents, vowel marks or tatweel, in lower case): never by
15
+ * a name that only sounds like one.
16
+ */
17
+ /** A place's names: in English, in Arabic, in French and German where they differ from English. */
18
+ export interface Known {
19
+ names: Partial<Record<Locale, string>> & {
20
+ en: string;
21
+ ar: string;
22
+ };
23
+ code?: string;
24
+ }
25
+ /**
26
+ * A name as two of Azure's answers write one place's: its words, without
27
+ * accents, tatweel, vowel marks or the direction marks Arabic carries, in
28
+ * lower case ("Ash Shāriqah" is "ash shariqah", "الشيـخ زايد" "الشيخ زايد").
29
+ */
30
+ export declare const nameKey: (name: unknown) => string;
31
+ /** A region (a governorate, a province, an emirate) of these countries, by Azure's code for it or by one of its names. */
32
+ export declare function knownRegion(country: string, ...names: string[]): Known | undefined;
33
+ /** A city of these countries, by one of its names. */
34
+ export declare function knownCity(country: string, name: string): Known | undefined;
35
+ /** A known place's name in a page's language: its own in French or German where it has one, its English one otherwise. */
36
+ export declare const nameIn: (known: Known, locale: Locale) => string;
37
+ /** Whether two names are one known city's or region's in a country ("Cairo" and "القاهرة"; "Al Jizah" and "Giza"). */
38
+ export declare function sameKnown(country: string, one: string, other: string): boolean;
@@ -0,0 +1,38 @@
1
+ import type { Locale } from '@fieldia/core';
2
+ /**
3
+ * What is known of the regions and cities of Egypt, Saudi Arabia, the UAE
4
+ * and Jordan, for reading Azure's addresses there, where each of its services
5
+ * names one place its own way: a region by its code ("RIY", "SH") or by a
6
+ * name ("Sharjah Emirate", "Ash Shāriqah", "منطقة الرياض", "مكة"), a city as
7
+ * a locality in another script ("Cairo" in an Arabic answer) or another
8
+ * spelling ("Ad Dammām", "الأسكندرية"). Each place here has one name in each
9
+ * language, which Fieldia writes, and every other name Azure was seen to give
10
+ * it (12–13 Oct 2026; each region's capital asked for in English and
11
+ * Arabic on 13 Oct). Loaded with the providers' address parts.
12
+ *
13
+ * A place is one of these only by its code or one of its names, the same
14
+ * words (without accents, vowel marks or tatweel, in lower case): never by
15
+ * a name that only sounds like one.
16
+ */
17
+ /** A place's names: in English, in Arabic, in French and German where they differ from English. */
18
+ export interface Known {
19
+ names: Partial<Record<Locale, string>> & {
20
+ en: string;
21
+ ar: string;
22
+ };
23
+ code?: string;
24
+ }
25
+ /**
26
+ * A name as two of Azure's answers write one place's: its words, without
27
+ * accents, tatweel, vowel marks or the direction marks Arabic carries, in
28
+ * lower case ("Ash Shāriqah" is "ash shariqah", "الشيـخ زايد" "الشيخ زايد").
29
+ */
30
+ export declare const nameKey: (name: unknown) => string;
31
+ /** A region (a governorate, a province, an emirate) of these countries, by Azure's code for it or by one of its names. */
32
+ export declare function knownRegion(country: string, ...names: string[]): Known | undefined;
33
+ /** A city of these countries, by one of its names. */
34
+ export declare function knownCity(country: string, name: string): Known | undefined;
35
+ /** A known place's name in a page's language: its own in French or German where it has one, its English one otherwise. */
36
+ export declare const nameIn: (known: Known, locale: Locale) => string;
37
+ /** Whether two names are one known city's or region's in a country ("Cairo" and "القاهرة"; "Al Jizah" and "Giza"). */
38
+ export declare function sameKnown(country: string, one: string, other: string): boolean;