@fieldia/map 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +75 -10
  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 +21 -0
  10. package/src/lib/address-labels.d.ts +21 -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 +2 -0
  16. package/src/lib/address-line.d.ts +2 -0
  17. package/src/lib/address-line.js +34 -0
  18. package/src/lib/address-line.js.map +1 -0
  19. package/src/lib/address-line.mjs +31 -0
  20. package/src/lib/address-line.mjs.map +1 -0
  21. package/src/lib/address-parts.d.mts +28 -0
  22. package/src/lib/address-parts.d.ts +28 -0
  23. package/src/lib/address-parts.js +47 -0
  24. package/src/lib/address-parts.js.map +1 -0
  25. package/src/lib/address-parts.mjs +38 -0
  26. package/src/lib/address-parts.mjs.map +1 -0
  27. package/src/lib/address-search.d.mts +21 -0
  28. package/src/lib/address-search.d.ts +21 -0
  29. package/src/lib/address-search.js +52 -0
  30. package/src/lib/address-search.js.map +1 -0
  31. package/src/lib/address-search.mjs +49 -0
  32. package/src/lib/address-search.mjs.map +1 -0
  33. package/src/lib/address-suggest.d.mts +18 -0
  34. package/src/lib/address-suggest.d.ts +18 -0
  35. package/src/lib/address-suggest.js +140 -0
  36. package/src/lib/address-suggest.js.map +1 -0
  37. package/src/lib/address-suggest.mjs +137 -0
  38. package/src/lib/address-suggest.mjs.map +1 -0
  39. package/src/lib/area-count.d.mts +47 -0
  40. package/src/lib/area-count.d.ts +47 -0
  41. package/src/lib/area-count.js +123 -0
  42. package/src/lib/area-count.js.map +1 -0
  43. package/src/lib/area-count.mjs +116 -0
  44. package/src/lib/area-count.mjs.map +1 -0
  45. package/src/lib/card.d.mts +16 -6
  46. package/src/lib/card.d.ts +16 -6
  47. package/src/lib/card.js +71 -14
  48. package/src/lib/card.js.map +1 -1
  49. package/src/lib/card.mjs +70 -14
  50. package/src/lib/card.mjs.map +1 -1
  51. package/src/lib/cluster.d.mts +6 -1
  52. package/src/lib/cluster.d.ts +6 -1
  53. package/src/lib/cluster.js +11 -5
  54. package/src/lib/cluster.js.map +1 -1
  55. package/src/lib/cluster.mjs +11 -5
  56. package/src/lib/cluster.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.d.mts +2 -1
  64. package/src/lib/form-map.d.ts +2 -1
  65. package/src/lib/form-map.js +159 -20
  66. package/src/lib/form-map.js.map +1 -1
  67. package/src/lib/form-map.mjs +161 -22
  68. package/src/lib/form-map.mjs.map +1 -1
  69. package/src/lib/kinds.d.mts +6 -4
  70. package/src/lib/kinds.d.ts +6 -4
  71. package/src/lib/kinds.js +49 -2
  72. package/src/lib/kinds.js.map +1 -1
  73. package/src/lib/kinds.mjs +49 -2
  74. package/src/lib/kinds.mjs.map +1 -1
  75. package/src/lib/labels.d.mts +5 -0
  76. package/src/lib/labels.d.ts +5 -0
  77. package/src/lib/labels.js +12 -4
  78. package/src/lib/labels.js.map +1 -1
  79. package/src/lib/labels.mjs +12 -4
  80. package/src/lib/labels.mjs.map +1 -1
  81. package/src/lib/leaflet.js +1 -0
  82. package/src/lib/leaflet.js.map +1 -1
  83. package/src/lib/leaflet.mjs +1 -0
  84. package/src/lib/leaflet.mjs.map +1 -1
  85. package/src/lib/list-view.d.mts +37 -1
  86. package/src/lib/list-view.d.ts +37 -1
  87. package/src/lib/list-view.js +103 -50
  88. package/src/lib/list-view.js.map +1 -1
  89. package/src/lib/list-view.mjs +103 -51
  90. package/src/lib/list-view.mjs.map +1 -1
  91. package/src/lib/map-core.d.mts +8 -3
  92. package/src/lib/map-core.d.ts +8 -3
  93. package/src/lib/map-core.js +21 -10
  94. package/src/lib/map-core.js.map +1 -1
  95. package/src/lib/map-core.mjs +21 -10
  96. package/src/lib/map-core.mjs.map +1 -1
  97. package/src/lib/marks.d.mts +11 -0
  98. package/src/lib/marks.d.ts +11 -0
  99. package/src/lib/marks.js +26 -1
  100. package/src/lib/marks.js.map +1 -1
  101. package/src/lib/marks.mjs +23 -0
  102. package/src/lib/marks.mjs.map +1 -1
  103. package/src/lib/pins.d.mts +20 -8
  104. package/src/lib/pins.d.ts +20 -8
  105. package/src/lib/pins.js +60 -15
  106. package/src/lib/pins.js.map +1 -1
  107. package/src/lib/pins.mjs +60 -17
  108. package/src/lib/pins.mjs.map +1 -1
  109. package/src/lib/place.js +2 -1
  110. package/src/lib/place.js.map +1 -1
  111. package/src/lib/place.mjs +2 -1
  112. package/src/lib/place.mjs.map +1 -1
  113. package/src/lib/providers.d.mts +31 -5
  114. package/src/lib/providers.d.ts +31 -5
  115. package/src/lib/providers.js +80 -58
  116. package/src/lib/providers.js.map +1 -1
  117. package/src/lib/providers.mjs +80 -58
  118. package/src/lib/providers.mjs.map +1 -1
  119. package/src/lib/regions.js +18 -1
  120. package/src/lib/regions.js.map +1 -1
  121. package/src/lib/regions.mjs +18 -1
  122. package/src/lib/regions.mjs.map +1 -1
  123. package/src/lib/search-box.d.mts +7 -1
  124. package/src/lib/search-box.d.ts +7 -1
  125. package/src/lib/search-box.js +15 -10
  126. package/src/lib/search-box.js.map +1 -1
  127. package/src/lib/search-box.mjs +15 -10
  128. package/src/lib/search-box.mjs.map +1 -1
  129. package/src/lib/settings.d.mts +19 -2
  130. package/src/lib/settings.d.ts +19 -2
  131. package/src/lib/styles.d.mts +13 -2
  132. package/src/lib/styles.d.ts +13 -2
  133. package/src/lib/styles.js +69 -4
  134. package/src/lib/styles.js.map +1 -1
  135. package/src/lib/styles.mjs +67 -3
  136. package/src/lib/styles.mjs.map +1 -1
  137. package/src/lib/tools.d.mts +6 -3
  138. package/src/lib/tools.d.ts +6 -3
  139. package/src/lib/tools.js +52 -1
  140. package/src/lib/tools.js.map +1 -1
  141. package/src/lib/tools.mjs +52 -1
  142. package/src/lib/tools.mjs.map +1 -1
  143. package/src/lib/view-box.d.mts +18 -0
  144. package/src/lib/view-box.d.ts +18 -0
  145. package/src/lib/view-box.js +31 -0
  146. package/src/lib/view-box.js.map +1 -0
  147. package/src/lib/view-box.mjs +25 -0
  148. package/src/lib/view-box.mjs.map +1 -0
  149. package/src/lib/widgets.d.mts +3 -0
  150. package/src/lib/widgets.d.ts +3 -0
  151. package/src/lib/widgets.js +10 -1
  152. package/src/lib/widgets.js.map +1 -1
  153. package/src/lib/widgets.mjs +10 -1
  154. package/src/lib/widgets.mjs.map +1 -1
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addressSearchWidget = addressSearchWidget;
4
+ const widgets_1 = require("@fieldia/widgets");
5
+ const address_line_1 = require("./address-line");
6
+ const search_box_1 = require("./search-box");
7
+ /**
8
+ * An address typed on one line (`"widget": "address-search"` on a char
9
+ * field), the addresses the map's provider suggests as people type in a list
10
+ * under it, and no map: the place search's own combobox, its pauses, its
11
+ * credits and its language. What is typed is the answer when nothing is
12
+ * picked. A suggestion picked writes its whole address, and where the page
13
+ * says, its place into a place field (`placeField`: a json field's GeoJSON
14
+ * Point, or a float field's latitude with `longitudeField` for its
15
+ * longitude) and its parts into an address field (`partsField`, a
16
+ * `json.address`: street, city, region, postcode and country, the line under
17
+ * the street kept as typed). `countries` (ISO codes) keeps the suggestions to
18
+ * those countries; `near` (`{ "lat", "lng" }`) puts those near it first, as
19
+ * where the app's maps open does unless it says.
20
+ *
21
+ * The box is the app's own text box, there at once; the suggestions come
22
+ * with their code, loaded the first time an address field is shown. With no
23
+ * address search to ask, the text box is all there is.
24
+ */
25
+ function addressSearchWidget(settings) {
26
+ return (context) => {
27
+ const plain = (0, widgets_1.createWidget)({ ...context, node: { ...context.node, widget: undefined } });
28
+ const search = settings.search ?? settings.provider.search;
29
+ const input = (plain.element.tagName === 'INPUT' ? plain.element : plain.element.querySelector('input'));
30
+ if (!search || !input)
31
+ return plain;
32
+ const element = context.document.createElement('div');
33
+ element.className = 'fd-address-search';
34
+ element.append(plain.element);
35
+ let stop;
36
+ // The place search's own combobox and line are handed over, as the page has them already: the suggestions' chunk carries neither.
37
+ Promise.resolve().then(() => require('./address-suggest')).then(({ suggest }) => {
38
+ if (stop === undefined)
39
+ stop = suggest({ settings, context, search, element, input, searchBox: search_box_1.searchBox, addressLine: address_line_1.addressLine });
40
+ });
41
+ return {
42
+ ...plain,
43
+ element,
44
+ destroy() {
45
+ stop?.();
46
+ stop = null;
47
+ plain.destroy?.();
48
+ },
49
+ };
50
+ };
51
+ }
52
+ //# sourceMappingURL=address-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address-search.js","sourceRoot":"","sources":["../../../../../libs/map/src/lib/address-search.ts"],"names":[],"mappings":";;AAuBA,kDAwBC;AA/CD,8CAAoE;AACpE,iDAA6C;AAC7C,6CAAyC;AAGzC;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,mBAAmB,CAAC,QAAqB;IACvD,OAAO,CAAC,OAAO,EAAE,EAAE;QACjB,MAAM,KAAK,GAAG,IAAA,sBAAY,EAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QACzF,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC3D,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAA4B,CAAC;QACpI,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QACpC,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACtD,OAAO,CAAC,SAAS,GAAG,mBAAmB,CAAC;QACxC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9B,IAAI,IAAqC,CAAC;QAC1C,kIAAkI;QAClI,qCAAO,mBAAmB,GAAE,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;YAC/C,IAAI,IAAI,KAAK,SAAS;gBAAE,IAAI,GAAG,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAT,sBAAS,EAAE,WAAW,EAAX,0BAAW,EAAE,CAAC,CAAC;QAChH,CAAC,CAAC,CAAC;QACH,OAAO;YACL,GAAG,KAAK;YACR,OAAO;YACP,OAAO;gBACL,IAAI,EAAE,EAAE,CAAC;gBACT,IAAI,GAAG,IAAI,CAAC;gBACZ,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YACpB,CAAC;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { createWidget } from '@fieldia/widgets';
2
+ import { addressLine } from './address-line.mjs';
3
+ import { searchBox } from './search-box.mjs';
4
+ /**
5
+ * An address typed on one line (`"widget": "address-search"` on a char
6
+ * field), the addresses the map's provider suggests as people type in a list
7
+ * under it, and no map: the place search's own combobox, its pauses, its
8
+ * credits and its language. What is typed is the answer when nothing is
9
+ * picked. A suggestion picked writes its whole address, and where the page
10
+ * says, its place into a place field (`placeField`: a json field's GeoJSON
11
+ * Point, or a float field's latitude with `longitudeField` for its
12
+ * longitude) and its parts into an address field (`partsField`, a
13
+ * `json.address`: street, city, region, postcode and country, the line under
14
+ * the street kept as typed). `countries` (ISO codes) keeps the suggestions to
15
+ * those countries; `near` (`{ "lat", "lng" }`) puts those near it first, as
16
+ * where the app's maps open does unless it says.
17
+ *
18
+ * The box is the app's own text box, there at once; the suggestions come
19
+ * with their code, loaded the first time an address field is shown. With no
20
+ * address search to ask, the text box is all there is.
21
+ */
22
+ export function addressSearchWidget(settings) {
23
+ return (context) => {
24
+ const plain = createWidget({ ...context, node: { ...context.node, widget: undefined } });
25
+ const search = settings.search ?? settings.provider.search;
26
+ const input = (plain.element.tagName === 'INPUT' ? plain.element : plain.element.querySelector('input'));
27
+ if (!search || !input)
28
+ return plain;
29
+ const element = context.document.createElement('div');
30
+ element.className = 'fd-address-search';
31
+ element.append(plain.element);
32
+ let stop;
33
+ // The place search's own combobox and line are handed over, as the page has them already: the suggestions' chunk carries neither.
34
+ import('./address-suggest.mjs').then(({ suggest }) => {
35
+ if (stop === undefined)
36
+ stop = suggest({ settings, context, search, element, input, searchBox, addressLine });
37
+ });
38
+ return {
39
+ ...plain,
40
+ element,
41
+ destroy() {
42
+ stop?.();
43
+ stop = null;
44
+ plain.destroy?.();
45
+ },
46
+ };
47
+ };
48
+ }
49
+ //# sourceMappingURL=address-search.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address-search.mjs","sourceRoot":"","sources":["../../../../../libs/map/src/lib/address-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAsB,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAqB;IACvD,OAAO,CAAC,OAAO,EAAE,EAAE;QACjB,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QACzF,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC3D,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAA4B,CAAC;QACpI,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QACpC,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACtD,OAAO,CAAC,SAAS,GAAG,mBAAmB,CAAC;QACxC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9B,IAAI,IAAqC,CAAC;QAC1C,kIAAkI;QAClI,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;YAC/C,IAAI,IAAI,KAAK,SAAS;gBAAE,IAAI,GAAG,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;QAChH,CAAC,CAAC,CAAC;QACH,OAAO;YACL,GAAG,KAAK;YACR,OAAO;YACP,OAAO;gBACL,IAAI,EAAE,EAAE,CAAC;gBACT,IAAI,GAAG,IAAI,CAAC;gBACZ,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YACpB,CAAC;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { WidgetContext } from '@fieldia/widgets';
2
+ import type { addressLine } from './address-line.mjs';
3
+ import type { AddressSearch } from './providers.mjs';
4
+ import type { searchBox } from './search-box.mjs';
5
+ import type { MapSettings } from './settings.mjs';
6
+ export interface SuggestOptions {
7
+ settings: MapSettings;
8
+ context: WidgetContext;
9
+ search: AddressSearch;
10
+ /** The field's box, and what holds it (and the list under it). */
11
+ element: HTMLElement;
12
+ input: HTMLInputElement;
13
+ /** The place search's combobox, and the line it writes. */
14
+ searchBox: typeof searchBox;
15
+ addressLine: typeof addressLine;
16
+ }
17
+ /** The suggestions on the field's box; what it gives back takes them off. */
18
+ export declare function suggest({ settings, context, search, element, input, searchBox, addressLine }: SuggestOptions): () => void;
@@ -0,0 +1,18 @@
1
+ import type { WidgetContext } from '@fieldia/widgets';
2
+ import type { addressLine } from './address-line';
3
+ import type { AddressSearch } from './providers';
4
+ import type { searchBox } from './search-box';
5
+ import type { MapSettings } from './settings';
6
+ export interface SuggestOptions {
7
+ settings: MapSettings;
8
+ context: WidgetContext;
9
+ search: AddressSearch;
10
+ /** The field's box, and what holds it (and the list under it). */
11
+ element: HTMLElement;
12
+ input: HTMLInputElement;
13
+ /** The place search's combobox, and the line it writes. */
14
+ searchBox: typeof searchBox;
15
+ addressLine: typeof addressLine;
16
+ }
17
+ /** The suggestions on the field's box; what it gives back takes them off. */
18
+ export declare function suggest({ settings, context, search, element, input, searchBox, addressLine }: SuggestOptions): () => void;
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.suggest = suggest;
4
+ const geo_1 = require("./geo");
5
+ const address_labels_1 = require("./address-labels");
6
+ const labels_1 = require("./labels");
7
+ const map_core_1 = require("./map-core");
8
+ const styles_1 = require("./styles");
9
+ /**
10
+ * An address field's suggestions (address-search.ts), loaded the first time
11
+ * one is shown: the place search's combobox on the field's own box, its list
12
+ * in a box of its own under it with the provider's credit, and what a
13
+ * suggestion picked writes.
14
+ */
15
+ /** The list as the place search draws it, in a box of its own with the credit under it; hidden with the list. */
16
+ const ADDRESS_CSS = `
17
+ .fd-address-search { position: relative; min-width: 0; }
18
+ .fd-address-popup {
19
+ position: absolute; inset-inline: 0; top: calc(100% + 4px); z-index: 1100; overflow: hidden;
20
+ background: var(--fd-surface); color: var(--fd-text); border: 1px solid var(--fd-border); border-radius: var(--fd-control-radius); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);
21
+ }
22
+ .fd-address-popup:has(> .fd-map-results[hidden]) { display: none; }
23
+ .fd-address-popup .fd-map-results { position: static; max-height: 264px; border: 0; border-radius: 0; box-shadow: none; background: none; }
24
+ .fd-address-credit { display: block; padding: 3px 10px 5px; border-top: 1px solid var(--fd-border); font-size: 11px; line-height: 1.4; color: var(--fd-muted); text-align: end; text-decoration: none; }
25
+ a.fd-address-credit:hover { text-decoration: underline; }
26
+ .fd-address-credit img { height: 14px; vertical-align: middle; }
27
+ `;
28
+ const round6 = (n) => Math.round(n * 1e6) / 1e6;
29
+ const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
30
+ /** The suggestions on the field's box; what it gives back takes them off. */
31
+ function suggest({ settings, context, search, element, input, searchBox, addressLine }) {
32
+ const { form, name, node, id, document: doc } = context;
33
+ const locale = context.locale ?? 'en';
34
+ const options = node.options ?? {};
35
+ const words = (0, address_labels_1.addressLabels)(locale, settings.labels?.[locale]);
36
+ const named = (key) => (typeof options[key] === 'string' ? options[key] : null);
37
+ const [placeField, longitudeField, partsField] = [named('placeField'), named('longitudeField'), named('partsField')];
38
+ const listed = options['countries'];
39
+ const countries = (Array.isArray(listed) ? listed.map(String) : typeof listed === 'string' ? listed.split(',') : []).map((code) => code.trim().toUpperCase()).filter(Boolean);
40
+ const near = isObject(options['near']) && (0, geo_1.isLatLng)(options['near']['lat'], options['near']['lng']) ? options['near'] : settings.center;
41
+ (0, styles_1.installMapStyles)(doc);
42
+ if (!doc.getElementById('fieldia-address-styles')) {
43
+ const style = doc.createElement('style');
44
+ style.id = 'fieldia-address-styles';
45
+ style.textContent = ADDRESS_CSS;
46
+ doc.head.prepend(style);
47
+ }
48
+ const status = doc.createElement('span');
49
+ status.className = 'fd-sr-only';
50
+ status.setAttribute('role', 'status');
51
+ /** Said to screen readers alone: how many suggestions came, or why none did. A typed address needs none to be an answer. */
52
+ const say = (said) => {
53
+ status.textContent = said ?? (box.list.hidden ? '' : (0, labels_1.fill)(words.suggested, { n: box.list.children.length }));
54
+ // Suggestions come: all of them in sight, as near the bottom of a phone's screen as the box is.
55
+ if (!box.list.hidden)
56
+ popup.scrollIntoView?.({ block: 'nearest' });
57
+ };
58
+ const write = (text) => {
59
+ input.value = text;
60
+ form.setValue(name, text || null);
61
+ };
62
+ let picking = 0;
63
+ const box = searchBox({
64
+ document: doc,
65
+ id,
66
+ input,
67
+ labels: words,
68
+ search: (request) => search({ ...request, ...(countries.length ? { countries } : {}), ...(partsField ? { parts: true } : {}) }),
69
+ asYouType: settings.search ? (settings.searchAsYouType ?? true) : !!settings.provider.searchAsYouType,
70
+ locale,
71
+ near: () => near,
72
+ zoom: () => settings.zoom,
73
+ freeText: true,
74
+ say,
75
+ // Its whole address at once; its place and parts as soon as they are known (looked up now, for a provider whose suggestions carry none).
76
+ async pick(place) {
77
+ const mine = ++picking;
78
+ const whole = addressLine([place.label, place.detail], locale);
79
+ write(whole);
80
+ let at = place.lat !== undefined && place.lng !== undefined ? { lat: place.lat, lng: place.lng } : null;
81
+ let parts = place.parts;
82
+ if (!at && place.locate && (placeField || (partsField && !parts))) {
83
+ const located = await place.locate().catch((error) => ((0, map_core_1.warnOnce)(`Finding the address picked failed: ${error.message}`), null));
84
+ if (mine !== picking || !located)
85
+ return;
86
+ at = located;
87
+ parts = located.parts ?? parts;
88
+ // The provider's own way of writing it, unless a person has typed since.
89
+ if (located.address && input.value === whole)
90
+ write(addressLine([located.address], locale));
91
+ }
92
+ if (at && placeField) {
93
+ if (form.page.fields[placeField]?.type !== 'float')
94
+ form.setValue(placeField, (0, geo_1.asJson)((0, geo_1.writePoint)(at)));
95
+ else if (longitudeField) {
96
+ form.setValue(placeField, round6(at.lat));
97
+ form.setValue(longitudeField, round6(at.lng));
98
+ }
99
+ }
100
+ if (parts && partsField) {
101
+ const now = form.getState().values[partsField];
102
+ const line2 = isObject(now) && typeof now['line2'] === 'string' ? { line2: now['line2'] } : {};
103
+ form.setValue(partsField, { ...parts, ...line2 });
104
+ }
105
+ },
106
+ });
107
+ // The list with what the provider's terms ask to be said under it: its mark, or its credit.
108
+ const popup = doc.createElement('div');
109
+ popup.className = 'fd-address-popup';
110
+ popup.append(box.list);
111
+ const mark = settings.search ? undefined : (settings.provider.logo ?? settings.provider.searchCredit);
112
+ if (mark) {
113
+ const credit = doc.createElement(mark.href ? 'a' : 'span');
114
+ credit.className = 'fd-address-credit';
115
+ if (mark.href)
116
+ Object.assign(credit, { href: mark.href, target: '_blank', rel: 'noopener', tabIndex: -1 });
117
+ const image = 'image' in mark ? mark.image : undefined;
118
+ if (image) {
119
+ const img = doc.createElement('img');
120
+ Object.assign(img, { src: image, alt: mark.text });
121
+ credit.append(img);
122
+ }
123
+ else {
124
+ // Its own words in their own direction: "© OpenStreetMap contributors" in an Arabic page too.
125
+ const text = doc.createElement('bdi');
126
+ text.textContent = mark.text;
127
+ credit.append(text);
128
+ }
129
+ popup.append(credit);
130
+ }
131
+ // A press on it keeps the box's focus, so the list stays open and a credit's link opens.
132
+ popup.addEventListener('mousedown', (event) => event.preventDefault());
133
+ element.append(popup, status);
134
+ return () => {
135
+ box.destroy();
136
+ popup.remove();
137
+ status.remove();
138
+ };
139
+ }
140
+ //# sourceMappingURL=address-suggest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address-suggest.js","sourceRoot":"","sources":["../../../../../libs/map/src/lib/address-suggest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,137 @@
1
+ import { asJson, isLatLng, writePoint } from './geo.mjs';
2
+ import { addressLabels } from './address-labels.mjs';
3
+ import { fill } from './labels.mjs';
4
+ import { warnOnce } from './map-core.mjs';
5
+ import { installMapStyles } from './styles.mjs';
6
+ /**
7
+ * An address field's suggestions (address-search.ts), loaded the first time
8
+ * one is shown: the place search's combobox on the field's own box, its list
9
+ * in a box of its own under it with the provider's credit, and what a
10
+ * suggestion picked writes.
11
+ */
12
+ /** The list as the place search draws it, in a box of its own with the credit under it; hidden with the list. */
13
+ const ADDRESS_CSS = `
14
+ .fd-address-search { position: relative; min-width: 0; }
15
+ .fd-address-popup {
16
+ position: absolute; inset-inline: 0; top: calc(100% + 4px); z-index: 1100; overflow: hidden;
17
+ background: var(--fd-surface); color: var(--fd-text); border: 1px solid var(--fd-border); border-radius: var(--fd-control-radius); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);
18
+ }
19
+ .fd-address-popup:has(> .fd-map-results[hidden]) { display: none; }
20
+ .fd-address-popup .fd-map-results { position: static; max-height: 264px; border: 0; border-radius: 0; box-shadow: none; background: none; }
21
+ .fd-address-credit { display: block; padding: 3px 10px 5px; border-top: 1px solid var(--fd-border); font-size: 11px; line-height: 1.4; color: var(--fd-muted); text-align: end; text-decoration: none; }
22
+ a.fd-address-credit:hover { text-decoration: underline; }
23
+ .fd-address-credit img { height: 14px; vertical-align: middle; }
24
+ `;
25
+ const round6 = (n) => Math.round(n * 1e6) / 1e6;
26
+ const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
27
+ /** The suggestions on the field's box; what it gives back takes them off. */
28
+ export function suggest({ settings, context, search, element, input, searchBox, addressLine }) {
29
+ const { form, name, node, id, document: doc } = context;
30
+ const locale = context.locale ?? 'en';
31
+ const options = node.options ?? {};
32
+ const words = addressLabels(locale, settings.labels?.[locale]);
33
+ const named = (key) => (typeof options[key] === 'string' ? options[key] : null);
34
+ const [placeField, longitudeField, partsField] = [named('placeField'), named('longitudeField'), named('partsField')];
35
+ const listed = options['countries'];
36
+ const countries = (Array.isArray(listed) ? listed.map(String) : typeof listed === 'string' ? listed.split(',') : []).map((code) => code.trim().toUpperCase()).filter(Boolean);
37
+ const near = isObject(options['near']) && isLatLng(options['near']['lat'], options['near']['lng']) ? options['near'] : settings.center;
38
+ installMapStyles(doc);
39
+ if (!doc.getElementById('fieldia-address-styles')) {
40
+ const style = doc.createElement('style');
41
+ style.id = 'fieldia-address-styles';
42
+ style.textContent = ADDRESS_CSS;
43
+ doc.head.prepend(style);
44
+ }
45
+ const status = doc.createElement('span');
46
+ status.className = 'fd-sr-only';
47
+ status.setAttribute('role', 'status');
48
+ /** Said to screen readers alone: how many suggestions came, or why none did. A typed address needs none to be an answer. */
49
+ const say = (said) => {
50
+ status.textContent = said ?? (box.list.hidden ? '' : fill(words.suggested, { n: box.list.children.length }));
51
+ // Suggestions come: all of them in sight, as near the bottom of a phone's screen as the box is.
52
+ if (!box.list.hidden)
53
+ popup.scrollIntoView?.({ block: 'nearest' });
54
+ };
55
+ const write = (text) => {
56
+ input.value = text;
57
+ form.setValue(name, text || null);
58
+ };
59
+ let picking = 0;
60
+ const box = searchBox({
61
+ document: doc,
62
+ id,
63
+ input,
64
+ labels: words,
65
+ search: (request) => search({ ...request, ...(countries.length ? { countries } : {}), ...(partsField ? { parts: true } : {}) }),
66
+ asYouType: settings.search ? (settings.searchAsYouType ?? true) : !!settings.provider.searchAsYouType,
67
+ locale,
68
+ near: () => near,
69
+ zoom: () => settings.zoom,
70
+ freeText: true,
71
+ say,
72
+ // Its whole address at once; its place and parts as soon as they are known (looked up now, for a provider whose suggestions carry none).
73
+ async pick(place) {
74
+ const mine = ++picking;
75
+ const whole = addressLine([place.label, place.detail], locale);
76
+ write(whole);
77
+ let at = place.lat !== undefined && place.lng !== undefined ? { lat: place.lat, lng: place.lng } : null;
78
+ let parts = place.parts;
79
+ if (!at && place.locate && (placeField || (partsField && !parts))) {
80
+ const located = await place.locate().catch((error) => (warnOnce(`Finding the address picked failed: ${error.message}`), null));
81
+ if (mine !== picking || !located)
82
+ return;
83
+ at = located;
84
+ parts = located.parts ?? parts;
85
+ // The provider's own way of writing it, unless a person has typed since.
86
+ if (located.address && input.value === whole)
87
+ write(addressLine([located.address], locale));
88
+ }
89
+ if (at && placeField) {
90
+ if (form.page.fields[placeField]?.type !== 'float')
91
+ form.setValue(placeField, asJson(writePoint(at)));
92
+ else if (longitudeField) {
93
+ form.setValue(placeField, round6(at.lat));
94
+ form.setValue(longitudeField, round6(at.lng));
95
+ }
96
+ }
97
+ if (parts && partsField) {
98
+ const now = form.getState().values[partsField];
99
+ const line2 = isObject(now) && typeof now['line2'] === 'string' ? { line2: now['line2'] } : {};
100
+ form.setValue(partsField, { ...parts, ...line2 });
101
+ }
102
+ },
103
+ });
104
+ // The list with what the provider's terms ask to be said under it: its mark, or its credit.
105
+ const popup = doc.createElement('div');
106
+ popup.className = 'fd-address-popup';
107
+ popup.append(box.list);
108
+ const mark = settings.search ? undefined : (settings.provider.logo ?? settings.provider.searchCredit);
109
+ if (mark) {
110
+ const credit = doc.createElement(mark.href ? 'a' : 'span');
111
+ credit.className = 'fd-address-credit';
112
+ if (mark.href)
113
+ Object.assign(credit, { href: mark.href, target: '_blank', rel: 'noopener', tabIndex: -1 });
114
+ const image = 'image' in mark ? mark.image : undefined;
115
+ if (image) {
116
+ const img = doc.createElement('img');
117
+ Object.assign(img, { src: image, alt: mark.text });
118
+ credit.append(img);
119
+ }
120
+ else {
121
+ // Its own words in their own direction: "© OpenStreetMap contributors" in an Arabic page too.
122
+ const text = doc.createElement('bdi');
123
+ text.textContent = mark.text;
124
+ credit.append(text);
125
+ }
126
+ popup.append(credit);
127
+ }
128
+ // A press on it keeps the box's focus, so the list stays open and a credit's link opens.
129
+ popup.addEventListener('mousedown', (event) => event.preventDefault());
130
+ element.append(popup, status);
131
+ return () => {
132
+ box.destroy();
133
+ popup.remove();
134
+ status.remove();
135
+ };
136
+ }
137
+ //# sourceMappingURL=address-suggest.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address-suggest.mjs","sourceRoot":"","sources":["../../../../../libs/map/src/lib/address-suggest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { ListMap, ResolvedFilter } from '@fieldia/core';
2
+ import type { LatLng } from './geo.mjs';
3
+ import { type Box } from './view-box.mjs';
4
+ /**
5
+ * How many records a list map's view holds, said on "Search this area"
6
+ * before it is pressed: counted among the records on hand when they can
7
+ * tell, asked otherwise. Its code comes the first time the button shows.
8
+ */
9
+ /** Whether a place lies in a box, its edges included, as `between` takes them. */
10
+ export declare function inBox(at: LatLng, box: Box): boolean;
11
+ /** Whether one box lies within another. */
12
+ export declare function boxWithin(inner: Box, outer: Box): boolean;
13
+ /**
14
+ * The view a search already holds, as the map's "Search this area" puts it
15
+ * (its very conditions, found among the search's), and the search's other
16
+ * conditions: a new view takes its place, as a search bar keeps one.
17
+ */
18
+ export declare function ownBox(spec: ListMap, filter: readonly ResolvedFilter[]): {
19
+ box: Box;
20
+ rest: ResolvedFilter[];
21
+ } | null;
22
+ /**
23
+ * One question at a time, the last one winning: each ask waits `wait`
24
+ * milliseconds (a run of moves asks once), aborts the one before it, and an
25
+ * answer that comes after a newer ask is dropped. A refusal says nothing.
26
+ */
27
+ export declare function lastAsk<T>(wait: number): {
28
+ ask(question: (signal: AbortSignal) => Promise<T>, answer: (value: T) => void): void;
29
+ stop: () => void;
30
+ };
31
+ /** What the map has on hand: the search its records were found by, whether they are all it finds, and where each is. */
32
+ export interface OnHand {
33
+ filter: readonly ResolvedFilter[];
34
+ all: boolean;
35
+ places: readonly (LatLng | null)[];
36
+ }
37
+ /**
38
+ * The count for a view: the records on hand say it when they are all the
39
+ * search finds and the view lies within any area it already holds;
40
+ * otherwise `ask` (the app's count, or its source's) is asked, for the
41
+ * search with the view in the area's place, a moment after the map stops;
42
+ * otherwise there is no number.
43
+ */
44
+ export declare function areaCounter(spec: ListMap, ask: ((filter: ResolvedFilter[], signal: AbortSignal) => Promise<number>) | null, say: (n: number) => void): {
45
+ count(view: Box, shown: OnHand): void;
46
+ stop: () => void;
47
+ };
@@ -0,0 +1,47 @@
1
+ import type { ListMap, ResolvedFilter } from '@fieldia/core';
2
+ import type { LatLng } from './geo';
3
+ import { type Box } from './view-box';
4
+ /**
5
+ * How many records a list map's view holds, said on "Search this area"
6
+ * before it is pressed: counted among the records on hand when they can
7
+ * tell, asked otherwise. Its code comes the first time the button shows.
8
+ */
9
+ /** Whether a place lies in a box, its edges included, as `between` takes them. */
10
+ export declare function inBox(at: LatLng, box: Box): boolean;
11
+ /** Whether one box lies within another. */
12
+ export declare function boxWithin(inner: Box, outer: Box): boolean;
13
+ /**
14
+ * The view a search already holds, as the map's "Search this area" puts it
15
+ * (its very conditions, found among the search's), and the search's other
16
+ * conditions: a new view takes its place, as a search bar keeps one.
17
+ */
18
+ export declare function ownBox(spec: ListMap, filter: readonly ResolvedFilter[]): {
19
+ box: Box;
20
+ rest: ResolvedFilter[];
21
+ } | null;
22
+ /**
23
+ * One question at a time, the last one winning: each ask waits `wait`
24
+ * milliseconds (a run of moves asks once), aborts the one before it, and an
25
+ * answer that comes after a newer ask is dropped. A refusal says nothing.
26
+ */
27
+ export declare function lastAsk<T>(wait: number): {
28
+ ask(question: (signal: AbortSignal) => Promise<T>, answer: (value: T) => void): void;
29
+ stop: () => void;
30
+ };
31
+ /** What the map has on hand: the search its records were found by, whether they are all it finds, and where each is. */
32
+ export interface OnHand {
33
+ filter: readonly ResolvedFilter[];
34
+ all: boolean;
35
+ places: readonly (LatLng | null)[];
36
+ }
37
+ /**
38
+ * The count for a view: the records on hand say it when they are all the
39
+ * search finds and the view lies within any area it already holds;
40
+ * otherwise `ask` (the app's count, or its source's) is asked, for the
41
+ * search with the view in the area's place, a moment after the map stops;
42
+ * otherwise there is no number.
43
+ */
44
+ export declare function areaCounter(spec: ListMap, ask: ((filter: ResolvedFilter[], signal: AbortSignal) => Promise<number>) | null, say: (n: number) => void): {
45
+ count(view: Box, shown: OnHand): void;
46
+ stop: () => void;
47
+ };