@mapka/maplibre-gl-sdk 0.16.1 → 0.16.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +10 -5
  2. package/lib/.buildInfo.json +1 -1
  3. package/lib/components/ImageCarousel.d.ts +7 -0
  4. package/lib/components/ImageCarousel.d.ts.map +1 -0
  5. package/lib/components/ImageCarousel.js +22 -0
  6. package/lib/components/PopupContent.d.ts +5 -1
  7. package/lib/components/PopupContent.d.ts.map +1 -1
  8. package/lib/components/PopupContent.js +12 -40
  9. package/lib/components/PopupDataRows.d.ts +7 -0
  10. package/lib/components/PopupDataRows.d.ts.map +1 -0
  11. package/lib/components/PopupDataRows.js +22 -0
  12. package/lib/components/PopupList.d.ts +10 -0
  13. package/lib/components/PopupList.d.ts.map +1 -0
  14. package/lib/components/PopupList.js +32 -0
  15. package/lib/components/icons/ChevronDownIcon.d.ts +2 -0
  16. package/lib/components/icons/ChevronDownIcon.d.ts.map +1 -0
  17. package/lib/components/icons/ChevronDownIcon.js +4 -0
  18. package/lib/components/icons/ChevronLeftIcon.d.ts +2 -0
  19. package/lib/components/icons/ChevronLeftIcon.d.ts.map +1 -0
  20. package/lib/components/icons/ChevronLeftIcon.js +4 -0
  21. package/lib/components/icons/ChevronRightIcon.d.ts +2 -0
  22. package/lib/components/icons/ChevronRightIcon.d.ts.map +1 -0
  23. package/lib/components/icons/ChevronRightIcon.js +4 -0
  24. package/lib/components/icons/ChevronUpIcon.d.ts +2 -0
  25. package/lib/components/icons/ChevronUpIcon.d.ts.map +1 -0
  26. package/lib/components/icons/ChevronUpIcon.js +4 -0
  27. package/lib/components/icons/CircleIcon.d.ts.map +1 -0
  28. package/lib/components/icons/CloseIcon.d.ts +2 -0
  29. package/lib/components/icons/CloseIcon.d.ts.map +1 -0
  30. package/lib/components/icons/CloseIcon.js +4 -0
  31. package/lib/components/icons/DownloadIcon.d.ts.map +1 -0
  32. package/lib/components/icons/FreehandIcon.d.ts.map +1 -0
  33. package/lib/components/icons/HeartIcon.d.ts +4 -0
  34. package/lib/components/icons/HeartIcon.d.ts.map +1 -0
  35. package/lib/components/icons/HeartIcon.js +4 -0
  36. package/lib/components/icons/LineIcon.d.ts.map +1 -0
  37. package/lib/components/icons/PencilIcon.d.ts.map +1 -0
  38. package/lib/components/icons/PolygonIcon.d.ts.map +1 -0
  39. package/lib/components/icons/ProgressDownIcon.d.ts +2 -0
  40. package/lib/components/icons/ProgressDownIcon.d.ts.map +1 -0
  41. package/lib/components/icons/RectangleIcon.d.ts.map +1 -0
  42. package/lib/components/icons/SelectIcon.d.ts.map +1 -0
  43. package/lib/components/icons/TrashIcon.d.ts.map +1 -0
  44. package/lib/controls/MapkaDrawControl.js +7 -7
  45. package/lib/controls/MapkaExportControl.js +2 -2
  46. package/lib/map.d.ts +8 -7
  47. package/lib/map.d.ts.map +1 -1
  48. package/lib/map.js +15 -9
  49. package/lib/modules/layerPopup.d.ts +2 -1
  50. package/lib/modules/layerPopup.d.ts.map +1 -1
  51. package/lib/modules/layerPopup.js +22 -15
  52. package/lib/modules/markers.d.ts +5 -0
  53. package/lib/modules/markers.d.ts.map +1 -1
  54. package/lib/modules/markers.js +21 -16
  55. package/lib/modules/popup.d.ts +3 -10
  56. package/lib/modules/popup.d.ts.map +1 -1
  57. package/lib/modules/popup.js +116 -100
  58. package/lib/modules/popupGroups.d.ts +14 -0
  59. package/lib/modules/popupGroups.d.ts.map +1 -0
  60. package/lib/modules/popupGroups.js +130 -0
  61. package/lib/styles.css +1 -1
  62. package/lib/types/popup.d.ts +10 -1
  63. package/lib/types/popup.d.ts.map +1 -1
  64. package/package.json +26 -7
  65. package/src/components/ImageCarousel.css +73 -0
  66. package/src/components/ImageCarousel.tsx +76 -0
  67. package/src/components/PopupContent.css +54 -189
  68. package/src/components/PopupContent.tsx +26 -195
  69. package/src/components/PopupDataRows.css +41 -0
  70. package/src/components/PopupDataRows.tsx +39 -0
  71. package/src/components/PopupList.css +71 -0
  72. package/src/components/PopupList.tsx +102 -0
  73. package/src/components/icons/ChevronDownIcon.tsx +20 -0
  74. package/src/components/icons/ChevronLeftIcon.tsx +20 -0
  75. package/src/components/icons/ChevronRightIcon.tsx +20 -0
  76. package/src/components/icons/ChevronUpIcon.tsx +20 -0
  77. package/src/components/icons/CloseIcon.tsx +13 -0
  78. package/src/components/icons/HeartIcon.tsx +18 -0
  79. package/src/components/{ProgressDownIcon.tsx → icons/ProgressDownIcon.tsx} +0 -3
  80. package/src/controls/MapkaDrawControl.css +1 -3
  81. package/src/controls/MapkaDrawControl.tsx +7 -7
  82. package/src/controls/MapkaExportControl.tsx +2 -2
  83. package/src/map.ts +28 -20
  84. package/src/modules/layerPopup.ts +32 -21
  85. package/src/modules/markers.ts +26 -16
  86. package/src/modules/popup.tsx +129 -112
  87. package/src/modules/popupGroups.ts +189 -0
  88. package/src/styles.css +3 -0
  89. package/src/types/popup.ts +12 -1
  90. package/lib/components/CircleIcon.d.ts.map +0 -1
  91. package/lib/components/DownloadIcon.d.ts.map +0 -1
  92. package/lib/components/FreehandIcon.d.ts.map +0 -1
  93. package/lib/components/LineIcon.d.ts.map +0 -1
  94. package/lib/components/PencilIcon.d.ts.map +0 -1
  95. package/lib/components/PolygonIcon.d.ts.map +0 -1
  96. package/lib/components/ProgressDownIcon.d.ts +0 -4
  97. package/lib/components/ProgressDownIcon.d.ts.map +0 -1
  98. package/lib/components/RectangleIcon.d.ts.map +0 -1
  99. package/lib/components/SelectIcon.d.ts.map +0 -1
  100. package/lib/components/TrashIcon.d.ts.map +0 -1
  101. /package/lib/components/{CircleIcon.d.ts → icons/CircleIcon.d.ts} +0 -0
  102. /package/lib/components/{CircleIcon.js → icons/CircleIcon.js} +0 -0
  103. /package/lib/components/{DownloadIcon.d.ts → icons/DownloadIcon.d.ts} +0 -0
  104. /package/lib/components/{DownloadIcon.js → icons/DownloadIcon.js} +0 -0
  105. /package/lib/components/{FreehandIcon.d.ts → icons/FreehandIcon.d.ts} +0 -0
  106. /package/lib/components/{FreehandIcon.js → icons/FreehandIcon.js} +0 -0
  107. /package/lib/components/{LineIcon.d.ts → icons/LineIcon.d.ts} +0 -0
  108. /package/lib/components/{LineIcon.js → icons/LineIcon.js} +0 -0
  109. /package/lib/components/{PencilIcon.d.ts → icons/PencilIcon.d.ts} +0 -0
  110. /package/lib/components/{PencilIcon.js → icons/PencilIcon.js} +0 -0
  111. /package/lib/components/{PolygonIcon.d.ts → icons/PolygonIcon.d.ts} +0 -0
  112. /package/lib/components/{PolygonIcon.js → icons/PolygonIcon.js} +0 -0
  113. /package/lib/components/{ProgressDownIcon.js → icons/ProgressDownIcon.js} +0 -0
  114. /package/lib/components/{RectangleIcon.d.ts → icons/RectangleIcon.d.ts} +0 -0
  115. /package/lib/components/{RectangleIcon.js → icons/RectangleIcon.js} +0 -0
  116. /package/lib/components/{SelectIcon.d.ts → icons/SelectIcon.d.ts} +0 -0
  117. /package/lib/components/{SelectIcon.js → icons/SelectIcon.js} +0 -0
  118. /package/lib/components/{TrashIcon.d.ts → icons/TrashIcon.d.ts} +0 -0
  119. /package/lib/components/{TrashIcon.js → icons/TrashIcon.js} +0 -0
  120. /package/src/components/{CircleIcon.tsx → icons/CircleIcon.tsx} +0 -0
  121. /package/src/components/{DownloadIcon.tsx → icons/DownloadIcon.tsx} +0 -0
  122. /package/src/components/{FreehandIcon.tsx → icons/FreehandIcon.tsx} +0 -0
  123. /package/src/components/{LineIcon.tsx → icons/LineIcon.tsx} +0 -0
  124. /package/src/components/{PencilIcon.tsx → icons/PencilIcon.tsx} +0 -0
  125. /package/src/components/{PolygonIcon.tsx → icons/PolygonIcon.tsx} +0 -0
  126. /package/src/components/{RectangleIcon.tsx → icons/RectangleIcon.tsx} +0 -0
  127. /package/src/components/{SelectIcon.tsx → icons/SelectIcon.tsx} +0 -0
  128. /package/src/components/{TrashIcon.tsx → icons/TrashIcon.tsx} +0 -0
@@ -0,0 +1,102 @@
1
+ import { useState } from "preact/hooks";
2
+ import type { MapkaPopupOptionsResolved } from "../types/popup.js";
3
+ import { PopupContent } from "./PopupContent.js";
4
+ import { ChevronUpIcon } from "./icons/ChevronUpIcon.js";
5
+ import { ChevronDownIcon } from "./icons/ChevronDownIcon.js";
6
+ import { noop } from "es-toolkit";
7
+
8
+ interface PopupCollectionProps {
9
+ items: MapkaPopupOptionsResolved[];
10
+ }
11
+
12
+ export function PopupCustomElement({ popup }: { popup: HTMLElement }) {
13
+ return popup;
14
+ }
15
+
16
+ interface PopupListNavProps {
17
+ index: number;
18
+ total: number;
19
+ onPrev: (e: Event) => void;
20
+ onNext: (e: Event) => void;
21
+ }
22
+
23
+ function PopupListNav({ index, total, onPrev, onNext }: PopupListNavProps) {
24
+ const isFirst = index === 0;
25
+ const isLast = index === total - 1;
26
+
27
+ return (
28
+ <div class="mapka-popup-list-nav">
29
+ <button
30
+ type="button"
31
+ class="mapka-popup-list-nav-btn"
32
+ onClick={onPrev}
33
+ disabled={isFirst}
34
+ aria-label="Previous popup"
35
+ >
36
+ <ChevronUpIcon />
37
+ </button>
38
+ <div class="mapka-popup-list-nav-counter">
39
+ <span>{index + 1}</span>
40
+ <span class="mapka-popup-list-nav-counter-divider" />
41
+ <span>{total}</span>
42
+ </div>
43
+ <button
44
+ type="button"
45
+ class="mapka-popup-list-nav-btn"
46
+ onClick={onNext}
47
+ disabled={isLast}
48
+ aria-label="Next popup"
49
+ >
50
+ <ChevronDownIcon />
51
+ </button>
52
+ </div>
53
+ );
54
+ }
55
+
56
+ export function PopupList({ items }: PopupCollectionProps) {
57
+ const [index, setIndex] = useState(0);
58
+ const safeIndex = Math.min(index, items.length - 1);
59
+
60
+ const handlePrev = (e: Event) => {
61
+ e.stopPropagation();
62
+ if (safeIndex > 0) {
63
+ setIndex(safeIndex - 1);
64
+ }
65
+ };
66
+
67
+ const handleNext = (e: Event) => {
68
+ e.stopPropagation();
69
+ if (safeIndex < items.length - 1) {
70
+ setIndex(safeIndex + 1);
71
+ }
72
+ };
73
+ const { id, content } = items[safeIndex];
74
+ return (
75
+ <div class="mapka-popup-list-wrapper">
76
+ <div class="mapka-popup-list">
77
+ {content instanceof HTMLElement ? (
78
+ <PopupCustomElement key={id} popup={content} />
79
+ ) : (
80
+ <PopupContent
81
+ key={id}
82
+ title={content.title}
83
+ description={content.description}
84
+ rows={content.rows}
85
+ imageUrls={content.imageUrls}
86
+ primaryAction={content.primaryAction}
87
+ closeButton={false}
88
+ onClose={noop}
89
+ />
90
+ )}
91
+ </div>
92
+ {items.length > 1 && (
93
+ <PopupListNav
94
+ index={safeIndex}
95
+ total={items.length}
96
+ onPrev={handlePrev}
97
+ onNext={handleNext}
98
+ />
99
+ )}
100
+ </div>
101
+ );
102
+ }
@@ -0,0 +1,20 @@
1
+ export function ChevronDownIcon() {
2
+ return (
3
+ <svg
4
+ viewBox="0 0 16 16"
5
+ xmlns="http://www.w3.org/2000/svg"
6
+ aria-hidden="true"
7
+ focusable="false"
8
+ class="mapka-popup-icon mapka-popup-icon-sm"
9
+ >
10
+ <path
11
+ d="M3 6 7.3 10.3a1 1 0 0 0 1.4 0L13 6"
12
+ fill="none"
13
+ stroke="currentColor"
14
+ stroke-width="1.5"
15
+ stroke-linecap="round"
16
+ stroke-linejoin="round"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ export function ChevronLeftIcon() {
2
+ return (
3
+ <svg
4
+ viewBox="0 0 16 16"
5
+ xmlns="http://www.w3.org/2000/svg"
6
+ aria-hidden="true"
7
+ focusable="false"
8
+ class="mapka-popup-icon mapka-popup-icon-sm"
9
+ >
10
+ <path
11
+ d="M10 3 5.7 7.3a1 1 0 0 0 0 1.4L10 13"
12
+ fill="none"
13
+ stroke="currentColor"
14
+ stroke-width="1.5"
15
+ stroke-linecap="round"
16
+ stroke-linejoin="round"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ export function ChevronRightIcon() {
2
+ return (
3
+ <svg
4
+ viewBox="0 0 16 16"
5
+ xmlns="http://www.w3.org/2000/svg"
6
+ aria-hidden="true"
7
+ focusable="false"
8
+ class="mapka-popup-icon mapka-popup-icon-sm"
9
+ >
10
+ <path
11
+ d="m6 3 4.3 4.3a1 1 0 0 1 0 1.4L6 13"
12
+ fill="none"
13
+ stroke="currentColor"
14
+ stroke-width="1.5"
15
+ stroke-linecap="round"
16
+ stroke-linejoin="round"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ export function ChevronUpIcon() {
2
+ return (
3
+ <svg
4
+ viewBox="0 0 16 16"
5
+ xmlns="http://www.w3.org/2000/svg"
6
+ aria-hidden="true"
7
+ focusable="false"
8
+ class="mapka-popup-icon mapka-popup-icon-sm"
9
+ >
10
+ <path
11
+ d="M3 10 7.3 5.7a1 1 0 0 1 1.4 0L13 10"
12
+ fill="none"
13
+ stroke="currentColor"
14
+ stroke-width="1.5"
15
+ stroke-linecap="round"
16
+ stroke-linejoin="round"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,13 @@
1
+ export function CloseIcon() {
2
+ return (
3
+ <svg
4
+ viewBox="0 0 32 32"
5
+ xmlns="http://www.w3.org/2000/svg"
6
+ aria-hidden="true"
7
+ focusable="false"
8
+ class="mapka-popup-icon"
9
+ >
10
+ <path d="m8 8 16 16M24 8 8 24" fill="none" stroke="currentColor" stroke-width="2" />
11
+ </svg>
12
+ );
13
+ }
@@ -0,0 +1,18 @@
1
+ export function HeartIcon({ filled }: { filled?: boolean }) {
2
+ return (
3
+ <svg
4
+ viewBox="0 0 32 32"
5
+ xmlns="http://www.w3.org/2000/svg"
6
+ aria-hidden="true"
7
+ focusable="false"
8
+ class="mapka-popup-icon"
9
+ >
10
+ <path
11
+ d="M16 28c7-4.73 14-10 14-17a6.98 6.98 0 0 0-7-7c-1.8 0-3.58.68-4.95 2.05L16 8.1l-2.05-2.05a6.98 6.98 0 0 0-9.9 0A6.98 6.98 0 0 0 2 11c0 7 7 12.27 14 17z"
12
+ fill={filled ? "currentColor" : "none"}
13
+ stroke="currentColor"
14
+ stroke-width="2"
15
+ />
16
+ </svg>
17
+ );
18
+ }
@@ -1,6 +1,3 @@
1
- /** biome-ignore-all lint/correctness/noUnusedImports: <explanation> */
2
- import { h } from "preact";
3
-
4
1
  export const ProgressDownIcon = () => {
5
2
  return (
6
3
  <svg
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  /* Draw Control Styles */
4
2
  .mapka-draw-control {
5
3
  display: flex;
@@ -50,4 +48,4 @@
50
48
  .mapka-draw-control-button--clear:hover {
51
49
  background-color: #fee2e2;
52
50
  color: #dc2626;
53
- }
51
+ }
@@ -10,13 +10,13 @@ import {
10
10
  TerraDrawFreehandMode,
11
11
  } from "terra-draw";
12
12
  import { TerraDrawMapLibreGLAdapter } from "terra-draw-maplibre-gl-adapter";
13
- import { SelectIcon } from "../components/SelectIcon.js";
14
- import { PolygonIcon } from "../components/PolygonIcon.js";
15
- import { RectangleIcon } from "../components/RectangleIcon.js";
16
- import { CircleIcon } from "../components/CircleIcon.js";
17
- import { LineIcon } from "../components/LineIcon.js";
18
- import { TrashIcon } from "../components/TrashIcon.js";
19
- import { FreehandIcon } from "../components/FreehandIcon.js";
13
+ import { SelectIcon } from "../components/icons/SelectIcon.js";
14
+ import { PolygonIcon } from "../components/icons/PolygonIcon.js";
15
+ import { RectangleIcon } from "../components/icons/RectangleIcon.js";
16
+ import { CircleIcon } from "../components/icons/CircleIcon.js";
17
+ import { LineIcon } from "../components/icons/LineIcon.js";
18
+ import { TrashIcon } from "../components/icons/TrashIcon.js";
19
+ import { FreehandIcon } from "../components/icons/FreehandIcon.js";
20
20
  import { isEmpty } from "es-toolkit/compat";
21
21
  import type { IControl } from "maplibre-gl";
22
22
  import type { GeoJSONStoreFeatures } from "terra-draw";
@@ -1,6 +1,6 @@
1
1
  import { render } from "preact";
2
- import { DownloadIcon } from "../components/DownloadIcon.js";
3
- import { ProgressDownIcon } from "../components/ProgressDownIcon.js";
2
+ import { DownloadIcon } from "../components/icons/DownloadIcon.js";
3
+ import { ProgressDownIcon } from "../components/icons/ProgressDownIcon.js";
4
4
  import type { IControl } from "maplibre-gl";
5
5
  import type { MapkaMap } from "../map.js";
6
6
  import type { MapkaExportOptions } from "../types/export.js";
package/src/map.ts CHANGED
@@ -1,13 +1,7 @@
1
1
  import * as maplibregl from "maplibre-gl";
2
2
  import { loadLayersIcons } from "./modules/icons.js";
3
3
  import { exportMap } from "./modules/export.js";
4
- import {
5
- closeOnMapClickPopups,
6
- closePopupsById,
7
- openPopup,
8
- removePopups,
9
- updatePopup,
10
- } from "./modules/popup.js";
4
+ import { closePopupsByIds, reconciliatePopups, closePopups } from "./modules/popup.js";
11
5
  import {
12
6
  addMarkers,
13
7
  addStyleDiffMarkers,
@@ -28,9 +22,9 @@ import type {
28
22
  } from "maplibre-gl";
29
23
  import type { MapkaMarkerOptions } from "./types/marker.js";
30
24
  import type { MapkaExportOptions } from "./types/export.js";
31
- import type { MapkaPopupOptions } from "./types/popup.js";
25
+ import type { MapkaPopupOptions, MapkaPopupOptionsResolved } from "./types/popup.js";
32
26
  import type { MapkaAddLayerObject } from "./types/layer.js";
33
- import { openOnFeatureClickPopups } from "./modules/layerPopup.js";
27
+ import { openClickPopups } from "./modules/layerPopup.js";
34
28
 
35
29
  export interface MapkaMapOptions extends MapOptions {
36
30
  maxPopups?: number;
@@ -65,8 +59,8 @@ const noopTransformStyle: TransformStyleFunction = (_, next) => {
65
59
  };
66
60
 
67
61
  export type MapMapkaPopup = {
68
- id: string | string[];
69
- options: MapkaPopupOptions;
62
+ ids: string[];
63
+ options: MapkaPopupOptionsResolved[];
70
64
  container: HTMLElement;
71
65
  popup: Popup;
72
66
  };
@@ -93,21 +87,31 @@ export class MapkaMap extends maplibregl.Map {
93
87
  public scrollPopups: boolean = true;
94
88
  public popups: MapMapkaPopup[] = [];
95
89
 
96
- public constructor({ transformRequest, apiKey, maxPopups = 1, ...options }: MapkaMapOptions) {
90
+ public constructor({
91
+ transformRequest,
92
+ apiKey,
93
+ maxPopups = 1,
94
+ scrollPopups = true,
95
+ ...options
96
+ }: MapkaMapOptions) {
97
97
  super({
98
98
  ...options,
99
99
  transformRequest: createTransformRequest(apiKey, transformRequest),
100
100
  });
101
101
 
102
102
  this.maxPopups = maxPopups;
103
+ this.scrollPopups = scrollPopups;
103
104
 
104
105
  super.on("styleimagemissing", (event: MapStyleImageMissingEvent) => {
105
106
  loadLayersIcons(this, event);
106
107
  });
107
108
 
108
109
  super.on("click", (event: maplibregl.MapMouseEvent) => {
109
- closeOnMapClickPopups(this);
110
- openOnFeatureClickPopups(this, event);
110
+ openClickPopups(this, event);
111
+ });
112
+
113
+ super.on("zoomend", () => {
114
+ reconciliatePopups(this);
111
115
  });
112
116
 
113
117
  super.on("style.load", () => {
@@ -144,20 +148,24 @@ export class MapkaMap extends maplibregl.Map {
144
148
  removeMarkers(this);
145
149
  }
146
150
 
147
- public openPopup(popup: MapkaPopupOptions) {
148
- return openPopup(this, popup);
151
+ public openPopup(popup: MapkaPopupOptions | MapkaPopupOptions[]) {
152
+ return reconciliatePopups(this, Array.isArray(popup) ? popup : [popup]);
149
153
  }
150
154
 
151
- public closePopup(id: string) {
152
- closePopupsById(this, id);
155
+ public closePopup(id: string | string[]) {
156
+ closePopupsByIds(this, Array.isArray(id) ? id : [id]);
153
157
  }
154
158
 
155
159
  public updatePopup(popup: MapkaPopupOptions) {
156
- return updatePopup(this, popup);
160
+ return reconciliatePopups(this, Array.isArray(popup) ? popup : [popup]);
161
+ }
162
+
163
+ public getPopups() {
164
+ return this.popups;
157
165
  }
158
166
 
159
167
  public removePopups() {
160
- removePopups(this);
168
+ closePopups(this);
161
169
  }
162
170
 
163
171
  public async export(options?: MapkaExportOptions) {
@@ -1,33 +1,16 @@
1
1
  import { get } from "es-toolkit/compat";
2
2
  import { isBoolean, isPlainObject } from "es-toolkit";
3
- import type { MapMouseEvent, MapGeoJSONFeature, LngLat } from "maplibre-gl";
3
+ import { closeOnMapClickPopups, getPopupId } from "./popup.js";
4
+ import type { MapMouseEvent, MapGeoJSONFeature, LngLat, Point } from "maplibre-gl";
4
5
  import type { MapkaMap } from "../map.js";
5
6
  import type { MapkaLayerPopupOptions } from "../types/popup.js";
6
7
  import type { MapkaPopupOptions } from "../types/popup.js";
7
8
 
8
- export function openOnFeatureClickPopups(map: MapkaMap, { lngLat, point }: MapMouseEvent) {
9
- const features = map.queryRenderedFeatures(point);
10
-
11
- if (features.length === 0) {
12
- return;
13
- }
14
-
15
- const popups = getFeaturePopups(features, lngLat);
16
-
17
- if (popups.length === 0) {
18
- return;
19
- }
20
-
21
- for (const popup of popups) {
22
- map.openPopup(popup);
23
- }
24
- }
25
-
26
9
  function genericPropertiesToPopup(feature: MapGeoJSONFeature, lngLat: LngLat): MapkaPopupOptions {
27
10
  const { id, properties, layer } = feature;
28
11
 
29
12
  return {
30
- id: id ?? properties.id,
13
+ id: id ?? properties.id ?? getPopupId(layer),
31
14
  lngLat: lngLat.toArray(),
32
15
  content: {
33
16
  title: layer.id,
@@ -46,7 +29,13 @@ function buildConfigDrivenPopup(
46
29
  throw new Error("Not implemented", { cause: { config, feature, lngLat } });
47
30
  }
48
31
 
49
- function getFeaturePopups(features: MapGeoJSONFeature[], lngLat: LngLat): MapkaPopupOptions[] {
32
+ function getFeaturePopups(
33
+ map: MapkaMap,
34
+ point: Point,
35
+ lngLat: LngLat,
36
+ trigger: "click" | "hover",
37
+ ): MapkaPopupOptions[] {
38
+ const features = map.queryRenderedFeatures(point);
50
39
  const popups: MapkaPopupOptions[] = [];
51
40
 
52
41
  for (const feature of features) {
@@ -66,9 +55,31 @@ function getFeaturePopups(features: MapGeoJSONFeature[], lngLat: LngLat): MapkaP
66
55
  }
67
56
 
68
57
  if (isPlainObject(mapkaPopup)) {
58
+ if (mapkaPopup.trigger && mapkaPopup.trigger !== trigger) {
59
+ continue;
60
+ }
69
61
  popups.push(buildConfigDrivenPopup(feature, mapkaPopup, lngLat));
70
62
  }
71
63
  }
72
64
 
73
65
  return popups;
74
66
  }
67
+
68
+ export function openClickPopups(map: MapkaMap, { lngLat, point }: MapMouseEvent) {
69
+ closeOnMapClickPopups(map);
70
+
71
+ const featurePopups = getFeaturePopups(map, point, lngLat, "click");
72
+ if (featurePopups.length === 0) {
73
+ return;
74
+ }
75
+ map.openPopup(featurePopups);
76
+ }
77
+
78
+ export function openOnHoverPopups(map: MapkaMap, { lngLat, point }: MapMouseEvent) {
79
+ const featurePopups = getFeaturePopups(map, point, lngLat, "hover");
80
+
81
+ if (featurePopups.length === 0) {
82
+ return;
83
+ }
84
+ map.openPopup(featurePopups);
85
+ }
@@ -1,6 +1,5 @@
1
1
  import { Marker } from "maplibre-gl";
2
2
  import { get } from "es-toolkit/compat";
3
- import { getPopupId } from "./popup.js";
4
3
  import { remove } from "es-toolkit";
5
4
  import type { Offset, StyleSpecification } from "maplibre-gl";
6
5
  import type { MapkaMap } from "../map.js";
@@ -26,17 +25,27 @@ export function getMarkerId(marker: { id?: string }) {
26
25
  return marker.id ?? `marker-${crypto.randomUUID()}`;
27
26
  }
28
27
 
29
- const markerPopupOptions = (marker: Marker, popupOptions: Omit<MapkaPopupOptions, "lngLat">) => {
28
+ export function getMarkerPopupId(marker: { id?: string }, popup: { id?: string }) {
29
+ return popup.id ?? marker.id ?? `marker-popup-${crypto.randomUUID()}`;
30
+ }
31
+
32
+ const markerPopupOptions = (
33
+ id: string,
34
+ marker: Marker,
35
+ popupOptions: Omit<MapkaPopupOptions, "lngLat">,
36
+ ) => {
30
37
  const latLng = marker.getLngLat().toArray();
31
38
 
32
39
  if ("offset" in popupOptions) {
33
40
  return {
34
41
  ...popupOptions,
42
+ id,
35
43
  lngLat: latLng,
36
44
  };
37
45
  } else {
38
46
  return {
39
47
  ...popupOptions,
48
+ id,
40
49
  lngLat: latLng,
41
50
  offset: DEFAULT_MARKET_OFFSET,
42
51
  };
@@ -49,51 +58,52 @@ function setupMarkerPopupListeners(
49
58
  popup: MapkaMarkerPopupOptions,
50
59
  options: MapkaMarkerOptions,
51
60
  ) {
52
- const popupId = getPopupId(popup);
53
61
  const markerElement = marker.getElement();
62
+ const popupId = getMarkerPopupId(options, popup);
63
+ const popupOptions = markerPopupOptions(popupId, marker, popup);
54
64
 
55
65
  if (options.draggable) {
56
66
  marker.on("dragend", () => {
57
- if (map.popups.find((p) => p.id === popupId)) {
58
- map.updatePopup(markerPopupOptions(marker, popup));
67
+ if (map.popups.find((p) => p.ids.includes(popupId))) {
68
+ map.updatePopup(popupOptions);
59
69
  }
60
70
  });
61
71
  marker.on("drag", () => {
62
- if (map.popups.find((p) => p.id === popupId)) {
63
- map.updatePopup(markerPopupOptions(marker, popup));
72
+ if (map.popups.find((p) => p.ids.includes(popupId))) {
73
+ map.updatePopup(popupOptions);
64
74
  }
65
75
  });
66
76
  }
67
77
 
68
78
  if (popup.trigger === "always") {
69
- if (!map.popups.find((p) => p.id === popupId)) {
70
- map.openPopup(markerPopupOptions(marker, popup));
79
+ if (!map.popups.find((p) => p.ids.includes(popupId))) {
80
+ map.openPopup(popupOptions);
71
81
  }
72
82
 
73
83
  markerElement.addEventListener("click", (e) => {
74
84
  e.stopPropagation();
75
- if (!map.popups.find((p) => p.id === popupId)) {
76
- map.openPopup(markerPopupOptions(marker, popup));
85
+ if (!map.popups.find((p) => p.ids.includes(popupId))) {
86
+ map.openPopup(popupOptions);
77
87
  }
78
88
  });
79
89
  } else if (popup.trigger === "click") {
80
90
  markerElement.style.cursor = "pointer";
81
91
  markerElement.addEventListener("click", (e) => {
82
92
  e.stopPropagation();
83
- if (!map.popups.find((p) => p.id === popupId)) {
84
- map.openPopup(markerPopupOptions(marker, popup));
93
+ if (!map.popups.find((p) => p.ids.includes(popupId))) {
94
+ map.openPopup(popupOptions);
85
95
  }
86
96
  });
87
97
  } else if (popup.trigger === "hover") {
88
98
  markerElement.addEventListener("mouseenter", (e) => {
89
99
  e.stopPropagation();
90
- if (!map.popups.find((p) => p.id === popupId)) {
91
- map.openPopup(markerPopupOptions(marker, popup));
100
+ if (!map.popups.find((p) => p.ids.includes(popupId))) {
101
+ map.openPopup(popupOptions);
92
102
  }
93
103
  });
94
104
  markerElement.addEventListener("mouseleave", (e) => {
95
105
  e.stopPropagation();
96
- if (map.popups.find((p) => p.id === popupId)) {
106
+ if (map.popups.find((p) => p.ids.includes(popupId))) {
97
107
  map.closePopup(popupId);
98
108
  }
99
109
  });