@mapka/maplibre-gl-sdk 0.16.1 → 0.16.3

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 (124) 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 +8 -0
  15. package/lib/components/PopupListItem.d.ts +13 -0
  16. package/lib/components/PopupListItem.d.ts.map +1 -0
  17. package/lib/components/PopupListItem.js +11 -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/CircleIcon.d.ts.map +1 -0
  25. package/lib/components/icons/CloseIcon.d.ts +2 -0
  26. package/lib/components/icons/CloseIcon.d.ts.map +1 -0
  27. package/lib/components/icons/CloseIcon.js +4 -0
  28. package/lib/components/icons/DownloadIcon.d.ts.map +1 -0
  29. package/lib/components/icons/FreehandIcon.d.ts.map +1 -0
  30. package/lib/components/icons/HeartIcon.d.ts +4 -0
  31. package/lib/components/icons/HeartIcon.d.ts.map +1 -0
  32. package/lib/components/icons/HeartIcon.js +4 -0
  33. package/lib/components/icons/LineIcon.d.ts.map +1 -0
  34. package/lib/components/icons/PencilIcon.d.ts.map +1 -0
  35. package/lib/components/icons/PolygonIcon.d.ts.map +1 -0
  36. package/lib/components/icons/ProgressDownIcon.d.ts +2 -0
  37. package/lib/components/icons/ProgressDownIcon.d.ts.map +1 -0
  38. package/lib/components/icons/RectangleIcon.d.ts.map +1 -0
  39. package/lib/components/icons/SelectIcon.d.ts.map +1 -0
  40. package/lib/components/icons/TrashIcon.d.ts.map +1 -0
  41. package/lib/controls/MapkaDrawControl.js +7 -7
  42. package/lib/controls/MapkaExportControl.js +2 -2
  43. package/lib/map.d.ts +8 -7
  44. package/lib/map.d.ts.map +1 -1
  45. package/lib/map.js +15 -9
  46. package/lib/modules/layerPopup.d.ts +2 -1
  47. package/lib/modules/layerPopup.d.ts.map +1 -1
  48. package/lib/modules/layerPopup.js +22 -15
  49. package/lib/modules/markers.d.ts +5 -0
  50. package/lib/modules/markers.d.ts.map +1 -1
  51. package/lib/modules/markers.js +21 -16
  52. package/lib/modules/popup.d.ts +3 -10
  53. package/lib/modules/popup.d.ts.map +1 -1
  54. package/lib/modules/popup.js +116 -100
  55. package/lib/modules/popupGroups.d.ts +14 -0
  56. package/lib/modules/popupGroups.d.ts.map +1 -0
  57. package/lib/modules/popupGroups.js +130 -0
  58. package/lib/styles.css +1 -1
  59. package/lib/types/popup.d.ts +10 -1
  60. package/lib/types/popup.d.ts.map +1 -1
  61. package/package.json +26 -7
  62. package/src/components/ImageCarousel.css +73 -0
  63. package/src/components/ImageCarousel.tsx +76 -0
  64. package/src/components/PopupContent.css +52 -189
  65. package/src/components/PopupContent.tsx +26 -195
  66. package/src/components/PopupDataRows.css +41 -0
  67. package/src/components/PopupDataRows.tsx +39 -0
  68. package/src/components/PopupList.css +24 -0
  69. package/src/components/PopupList.tsx +27 -0
  70. package/src/components/PopupListItem.css +61 -0
  71. package/src/components/PopupListItem.tsx +40 -0
  72. package/src/components/icons/ChevronLeftIcon.tsx +20 -0
  73. package/src/components/icons/ChevronRightIcon.tsx +20 -0
  74. package/src/components/icons/CloseIcon.tsx +13 -0
  75. package/src/components/icons/HeartIcon.tsx +18 -0
  76. package/src/components/{ProgressDownIcon.tsx → icons/ProgressDownIcon.tsx} +0 -3
  77. package/src/controls/MapkaDrawControl.tsx +7 -7
  78. package/src/controls/MapkaExportControl.tsx +2 -2
  79. package/src/map.ts +22 -20
  80. package/src/modules/layerPopup.ts +32 -21
  81. package/src/modules/markers.ts +26 -16
  82. package/src/modules/popup.tsx +129 -112
  83. package/src/modules/popupGroups.ts +190 -0
  84. package/src/styles.css +4 -0
  85. package/src/types/popup.ts +12 -1
  86. package/lib/components/CircleIcon.d.ts.map +0 -1
  87. package/lib/components/DownloadIcon.d.ts.map +0 -1
  88. package/lib/components/FreehandIcon.d.ts.map +0 -1
  89. package/lib/components/LineIcon.d.ts.map +0 -1
  90. package/lib/components/PencilIcon.d.ts.map +0 -1
  91. package/lib/components/PolygonIcon.d.ts.map +0 -1
  92. package/lib/components/ProgressDownIcon.d.ts +0 -4
  93. package/lib/components/ProgressDownIcon.d.ts.map +0 -1
  94. package/lib/components/RectangleIcon.d.ts.map +0 -1
  95. package/lib/components/SelectIcon.d.ts.map +0 -1
  96. package/lib/components/TrashIcon.d.ts.map +0 -1
  97. /package/lib/components/{CircleIcon.d.ts → icons/CircleIcon.d.ts} +0 -0
  98. /package/lib/components/{CircleIcon.js → icons/CircleIcon.js} +0 -0
  99. /package/lib/components/{DownloadIcon.d.ts → icons/DownloadIcon.d.ts} +0 -0
  100. /package/lib/components/{DownloadIcon.js → icons/DownloadIcon.js} +0 -0
  101. /package/lib/components/{FreehandIcon.d.ts → icons/FreehandIcon.d.ts} +0 -0
  102. /package/lib/components/{FreehandIcon.js → icons/FreehandIcon.js} +0 -0
  103. /package/lib/components/{LineIcon.d.ts → icons/LineIcon.d.ts} +0 -0
  104. /package/lib/components/{LineIcon.js → icons/LineIcon.js} +0 -0
  105. /package/lib/components/{PencilIcon.d.ts → icons/PencilIcon.d.ts} +0 -0
  106. /package/lib/components/{PencilIcon.js → icons/PencilIcon.js} +0 -0
  107. /package/lib/components/{PolygonIcon.d.ts → icons/PolygonIcon.d.ts} +0 -0
  108. /package/lib/components/{PolygonIcon.js → icons/PolygonIcon.js} +0 -0
  109. /package/lib/components/{ProgressDownIcon.js → icons/ProgressDownIcon.js} +0 -0
  110. /package/lib/components/{RectangleIcon.d.ts → icons/RectangleIcon.d.ts} +0 -0
  111. /package/lib/components/{RectangleIcon.js → icons/RectangleIcon.js} +0 -0
  112. /package/lib/components/{SelectIcon.d.ts → icons/SelectIcon.d.ts} +0 -0
  113. /package/lib/components/{SelectIcon.js → icons/SelectIcon.js} +0 -0
  114. /package/lib/components/{TrashIcon.d.ts → icons/TrashIcon.d.ts} +0 -0
  115. /package/lib/components/{TrashIcon.js → icons/TrashIcon.js} +0 -0
  116. /package/src/components/{CircleIcon.tsx → icons/CircleIcon.tsx} +0 -0
  117. /package/src/components/{DownloadIcon.tsx → icons/DownloadIcon.tsx} +0 -0
  118. /package/src/components/{FreehandIcon.tsx → icons/FreehandIcon.tsx} +0 -0
  119. /package/src/components/{LineIcon.tsx → icons/LineIcon.tsx} +0 -0
  120. /package/src/components/{PencilIcon.tsx → icons/PencilIcon.tsx} +0 -0
  121. /package/src/components/{PolygonIcon.tsx → icons/PolygonIcon.tsx} +0 -0
  122. /package/src/components/{RectangleIcon.tsx → icons/RectangleIcon.tsx} +0 -0
  123. /package/src/components/{SelectIcon.tsx → icons/SelectIcon.tsx} +0 -0
  124. /package/src/components/{TrashIcon.tsx → icons/TrashIcon.tsx} +0 -0
@@ -1,4 +1,3 @@
1
-
2
1
  /* Mapka Popup Styles */
3
2
  .mapka-popup-container {
4
3
  margin-top: -15px;
@@ -6,234 +5,98 @@
6
5
  margin-left: -10px;
7
6
  margin-right: -10px;
8
7
  }
8
+
9
9
  .mapka-popup {
10
10
  position: relative;
11
+ display: flex;
12
+ flex-direction: column;
13
+ align-items: flex-start;
14
+ background: #fff;
15
+ border: 1px solid #dcdfe3;
11
16
  border-radius: 12px;
12
17
  overflow: hidden;
13
- background: #fff;
14
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
18
+ box-shadow:
19
+ 0px 4px 32px -4px rgba(69, 72, 76, 0.12),
20
+ 0px 3px 12px -2px rgba(173, 181, 189, 0.06);
15
21
  }
16
22
 
17
- /* Close Button */
18
23
  .mapka-popup-close-btn {
19
24
  position: absolute;
20
25
  top: 10px;
21
26
  right: 10px;
22
- background: rgba(255, 255, 255, 0.8);
23
- border: none;
24
- border-radius: 6px;
25
- width: 24px;
26
- height: 24px;
27
- cursor: pointer;
28
- display: flex;
29
- align-items: center;
30
- justify-content: center;
31
- z-index: 4;
32
- color: #222;
33
- transition: background 0.2s ease;
34
- }
35
-
36
- .mapka-popup-close-btn:hover {
37
- background: #f4f4f7;
38
- }
39
-
40
- .mapka-popup-icon {
41
- display: block;
42
- fill: none;
43
- height: 16px;
44
- width: 16px;
45
- stroke: currentColor;
46
- overflow: visible;
47
- }
48
-
49
- .mapka-popup-icon-sm {
50
- height: 12px;
51
- width: 12px;
52
- }
53
-
54
- /* Carousel */
55
- .mapka-popup-carousel {
56
- position: relative;
57
- width: 100%;
58
- height: 200px;
59
- overflow: hidden;
60
- border-radius: 12px 12px 0 0;
61
- }
62
-
63
- .mapka-popup-carousel-track {
64
- display: flex;
65
- height: 100%;
66
- transition: transform 0.3s ease;
67
- }
68
-
69
- .mapka-popup-carousel-image {
70
- min-width: 100%;
71
- height: 100%;
72
- object-fit: cover;
73
- flex-shrink: 0;
74
- }
75
-
76
- .mapka-popup-carousel-actions {
77
- position: absolute;
78
- top: 12px;
79
- right: 12px;
80
- display: flex;
81
- gap: 8px;
82
- z-index: 3;
83
- }
84
-
85
- .mapka-popup-action-btn {
86
- background: rgba(255, 255, 255, 0.95);
87
- border: none;
88
- border-radius: 50%;
89
- width: 32px;
90
- height: 32px;
91
- cursor: pointer;
92
- display: flex;
93
- align-items: center;
94
- justify-content: center;
95
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.18);
96
- transition: background 0.2s ease, transform 0.2s ease;
97
- color: #222;
98
- }
99
-
100
- .mapka-popup-action-btn:hover {
101
- background: #fff;
102
- transform: scale(1.05);
103
- }
104
-
105
- .mapka-popup-carousel-btn {
106
- position: absolute;
107
- top: 50%;
108
- transform: translateY(-50%);
109
- background: rgba(255, 255, 255, 0.7);
110
- backdrop-filter: blur(3px);
111
- border: 1px solid #dcdfe3;
112
- border-radius: 100px;
113
- width: 32px;
114
- height: 32px;
115
- cursor: pointer;
27
+ z-index: 2;
116
28
  display: flex;
117
29
  align-items: center;
118
30
  justify-content: center;
119
- z-index: 2;
120
- transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
121
- color: #222;
122
- }
123
-
124
- .mapka-popup-carousel-btn:hover {
125
- background: #262626;
126
- border-color: #262626;
127
- color: #fff;
128
- }
129
-
130
- .mapka-popup-carousel-prev {
131
- left: 12px;
132
- }
133
-
134
- .mapka-popup-carousel-next {
135
- right: 12px;
136
- }
137
-
138
- .mapka-popup-dots {
139
- position: absolute;
140
- bottom: 12px;
141
- left: 50%;
142
- transform: translateX(-50%);
143
- display: flex;
144
- gap: 6px;
145
- z-index: 2;
146
- }
147
-
148
- .mapka-popup-dot {
149
- width: 6px;
150
- height: 6px;
151
- border-radius: 50%;
152
- background: rgba(255, 255, 255, 0.6);
31
+ width: 24px;
32
+ height: 24px;
33
+ border-radius: 6px;
153
34
  border: none;
35
+ background: rgba(255, 255, 255, 0.8);
154
36
  cursor: pointer;
155
37
  padding: 0;
156
- transition: background 0.2s ease, transform 0.2s ease;
38
+ color: #4f4f4f;
157
39
  }
158
40
 
159
- .mapka-popup-dot:hover {
160
- background: rgba(255, 255, 255, 0.8);
161
- transform: scale(1.2);
41
+ .mapka-popup-close-btn .mapka-popup-icon {
42
+ width: 16px;
43
+ height: 16px;
162
44
  }
163
45
 
164
- .mapka-popup-dot-active {
165
- background: #fff;
46
+ .mapka-popup-close-btn:hover {
47
+ background: rgba(255, 255, 255, 0.95);
166
48
  }
167
49
 
168
- /* Content */
169
50
  .mapka-popup-content {
170
- padding: 12px 16px 16px;
51
+ display: flex;
52
+ flex-direction: column;
53
+ align-items: flex-start;
54
+ gap: 12px;
55
+ padding: 16px;
56
+ width: 100%;
57
+ box-sizing: border-box;
171
58
  }
172
59
 
173
60
  .mapka-popup-title {
174
61
  margin: 0;
175
- font-size: 15px;
176
- font-weight: 600;
177
- color: #222;
178
- line-height: 1.3;
179
- flex: 1;
62
+ font-weight: 700;
63
+ font-size: 20px;
64
+ line-height: 28px;
65
+ color: #4f4f4f;
180
66
  }
181
67
 
182
68
  .mapka-popup-description {
183
- margin: 0 0 4px 0;
69
+ margin: 0;
70
+ font-weight: 400;
184
71
  font-size: 14px;
185
- color: #717171;
186
- line-height: 1.4;
187
- overflow: hidden;
188
- text-overflow: ellipsis;
189
- display: -webkit-box;
190
- -webkit-line-clamp: 2;
191
- -webkit-box-orient: vertical;
72
+ line-height: 18px;
73
+ color: #4f4f4f;
192
74
  }
193
75
 
194
- /* Rows */
195
- .mapka-popup-rows {
196
- margin: 12px 0 0 0;
197
- padding: 12px 0 0 0;
198
- border-top: 1px solid #ebebeb;
76
+ .mapka-popup-actions {
199
77
  display: flex;
200
- flex-direction: column;
78
+ gap: 8px;
79
+ align-items: flex-start;
80
+ width: 100%;
201
81
  }
202
82
 
203
- .mapka-popup-row {
83
+ .mapka-popup-button-primary {
204
84
  display: flex;
205
- gap: 16px;
206
- height: 38px;
207
85
  align-items: center;
208
- padding: 0 8px;
86
+ justify-content: center;
87
+ gap: 8px;
88
+ flex: 1;
89
+ padding: 10px 16px;
90
+ background: #4f4f4f;
91
+ border: none;
209
92
  border-radius: 6px;
210
- transition: background 0.2s ease;
211
- }
212
-
213
- .mapka-popup-row:hover {
214
- background: #f4f4f7;
215
- }
216
-
217
- .mapka-popup-row-label {
218
- font-size: 14px;
93
+ cursor: pointer;
219
94
  font-weight: 500;
95
+ font-size: 14px;
220
96
  line-height: 18px;
221
- color: #4f4f4f;
222
- margin: 0;
223
- white-space: nowrap;
224
- overflow: hidden;
225
- text-overflow: ellipsis;
226
- flex: 1;
97
+ color: #fff;
227
98
  }
228
99
 
229
- .mapka-popup-row-value {
230
- font-size: 14px;
231
- font-weight: 400;
232
- line-height: 18px;
233
- color: #4f4f4f;
234
- margin: 0;
235
- text-align: right;
236
- white-space: nowrap;
237
- overflow: hidden;
238
- text-overflow: ellipsis;
239
- }
100
+ .mapka-popup-button-primary:hover {
101
+ background: #3a3a3a;
102
+ }
@@ -1,188 +1,32 @@
1
- import { Fragment } from "preact";
2
- import { useState } from "preact/hooks";
1
+ import type { MouseEventHandler } from "preact";
3
2
  import type { MapkaPopupContent } from "../types/popup.js";
3
+ import { CloseIcon } from "./icons/CloseIcon.js";
4
+ import { PopupDataRows } from "./PopupDataRows.js";
5
+ import { ImageCarousel } from "./ImageCarousel.js";
4
6
 
5
7
  interface PopupProps extends MapkaPopupContent {
6
8
  onClose?: () => void;
7
9
  closeButton?: boolean;
8
10
  }
9
11
 
10
- function HeartIcon({ filled }: { filled?: boolean }) {
11
- return (
12
- <svg
13
- viewBox="0 0 32 32"
14
- xmlns="http://www.w3.org/2000/svg"
15
- aria-hidden="true"
16
- focusable="false"
17
- class="mapka-popup-icon"
18
- >
19
- <path
20
- 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"
21
- fill={filled ? "currentColor" : "none"}
22
- stroke="currentColor"
23
- stroke-width="2"
24
- />
25
- </svg>
26
- );
27
- }
28
-
29
- function CloseIcon() {
30
- return (
31
- <svg
32
- viewBox="0 0 32 32"
33
- xmlns="http://www.w3.org/2000/svg"
34
- aria-hidden="true"
35
- focusable="false"
36
- class="mapka-popup-icon"
37
- >
38
- <path d="m8 8 16 16M24 8 8 24" fill="none" stroke="currentColor" stroke-width="2" />
39
- </svg>
40
- );
41
- }
12
+ function PrimaryButton({ label, onClick }: { label: string; onClick?: () => void }) {
13
+ const handleClick = (e: Event) => {
14
+ e.stopPropagation();
15
+ onClick?.();
16
+ };
42
17
 
43
- function ChevronLeftIcon() {
44
18
  return (
45
- <svg
46
- viewBox="0 0 32 32"
47
- xmlns="http://www.w3.org/2000/svg"
48
- aria-hidden="true"
49
- focusable="false"
50
- class="mapka-popup-icon mapka-popup-icon-sm"
51
- >
52
- <path
53
- d="M20 28 8.7 16.7a1 1 0 0 1 0-1.4L20 4"
54
- fill="none"
55
- stroke="currentColor"
56
- stroke-width="4"
57
- />
58
- </svg>
19
+ <button type="button" class="mapka-popup-button-primary" onClick={handleClick}>
20
+ {label}
21
+ </button>
59
22
  );
60
23
  }
61
24
 
62
- function ChevronRightIcon() {
25
+ export function CloseButton({ onClose }: { onClose?: MouseEventHandler<HTMLButtonElement> }) {
63
26
  return (
64
- <svg
65
- viewBox="0 0 32 32"
66
- xmlns="http://www.w3.org/2000/svg"
67
- aria-hidden="true"
68
- focusable="false"
69
- class="mapka-popup-icon mapka-popup-icon-sm"
70
- >
71
- <path
72
- d="m12 4 11.3 11.3a1 1 0 0 1 0 1.4L12 28"
73
- fill="none"
74
- stroke="currentColor"
75
- stroke-width="4"
76
- />
77
- </svg>
78
- );
79
- }
80
-
81
- function ImageCarousel({
82
- imageUrls,
83
- title,
84
- onFavorite,
85
- id,
86
- }: {
87
- imageUrls: string[];
88
- title?: string;
89
- onFavorite?: (id: string) => void;
90
- id?: string;
91
- }) {
92
- const [currentIndex, setCurrentIndex] = useState(0);
93
- const isFirstImage = currentIndex === 0;
94
- const isLastImage = currentIndex === imageUrls.length - 1;
95
-
96
- const handlePrev = (e: Event) => {
97
- e.stopPropagation();
98
- if (currentIndex > 0) {
99
- setCurrentIndex((prev) => prev - 1);
100
- }
101
- };
102
-
103
- const handleNext = (e: Event) => {
104
- e.stopPropagation();
105
- if (currentIndex < imageUrls.length - 1) {
106
- setCurrentIndex((prev) => prev + 1);
107
- }
108
- };
109
-
110
- const handleFavoriteClick = (e: Event) => {
111
- e.stopPropagation();
112
- if (onFavorite && id) {
113
- onFavorite(id);
114
- }
115
- };
116
-
117
- return (
118
- <div class="mapka-popup-carousel">
119
- <div
120
- class="mapka-popup-carousel-track"
121
- style={{ transform: `translateX(-${currentIndex * 100}%)` }}
122
- >
123
- {imageUrls.map((url, index) => (
124
- <img
125
- key={index}
126
- src={url}
127
- alt={title || `Image ${index + 1}`}
128
- class="mapka-popup-carousel-image mapka-popup-image"
129
- />
130
- ))}
131
- </div>
132
-
133
- {onFavorite && (
134
- <div class="mapka-popup-carousel-actions">
135
- <button
136
- type="button"
137
- class="mapka-popup-action-btn"
138
- onClick={handleFavoriteClick}
139
- aria-label="Add to favorites"
140
- >
141
- <HeartIcon />
142
- </button>
143
- </div>
144
- )}
145
-
146
- {imageUrls.length > 1 && (
147
- <Fragment>
148
- {!isFirstImage && (
149
- <button
150
- type="button"
151
- class="mapka-popup-carousel-btn mapka-popup-carousel-prev"
152
- onClick={handlePrev}
153
- aria-label="Previous image"
154
- >
155
- <ChevronLeftIcon />
156
- </button>
157
- )}
158
- {!isLastImage && (
159
- <button
160
- type="button"
161
- class="mapka-popup-carousel-btn mapka-popup-carousel-next"
162
- onClick={handleNext}
163
- aria-label="Next image"
164
- >
165
- <ChevronRightIcon />
166
- </button>
167
- )}
168
-
169
- <div class="mapka-popup-dots">
170
- {imageUrls.map((_, index) => (
171
- <button
172
- key={index}
173
- type="button"
174
- class={`mapka-popup-dot ${index === currentIndex ? "mapka-popup-dot-active" : ""}`}
175
- onClick={(e) => {
176
- e.stopPropagation();
177
- setCurrentIndex(index);
178
- }}
179
- aria-label={`Go to image ${index + 1}`}
180
- />
181
- ))}
182
- </div>
183
- </Fragment>
184
- )}
185
- </div>
27
+ <button type="button" class="mapka-popup-close-btn" onClick={onClose} aria-label="Close">
28
+ <CloseIcon />
29
+ </button>
186
30
  );
187
31
  }
188
32
 
@@ -191,8 +35,8 @@ export function PopupContent({
191
35
  description,
192
36
  rows,
193
37
  closeButton,
194
- imageUrls,
195
- onFavorite,
38
+ imageUrls = [],
39
+ primaryAction,
196
40
  onClose,
197
41
  }: PopupProps) {
198
42
  const hasImages = imageUrls && imageUrls.length > 0;
@@ -205,32 +49,19 @@ export function PopupContent({
205
49
 
206
50
  return (
207
51
  <div class="mapka-popup">
208
- {closeButton && (
209
- <button
210
- type="button"
211
- class="mapka-popup-close-btn"
212
- onClick={handleCloseClick}
213
- aria-label="Close"
214
- >
215
- <CloseIcon />
216
- </button>
217
- )}
218
-
219
- {hasImages && <ImageCarousel imageUrls={imageUrls} title={title} onFavorite={onFavorite} />}
52
+ {closeButton && <CloseButton onClose={handleCloseClick} />}
53
+ {hasImages && <ImageCarousel imageUrls={imageUrls} title={title} />}
220
54
 
221
55
  <div class="mapka-popup-content">
222
56
  {title && <h3 class="mapka-popup-title">{title}</h3>}
223
57
  {description && <p class="mapka-popup-description">{description}</p>}
224
58
 
225
- {hasRows && (
226
- <dl class="mapka-popup-rows">
227
- {rows.map((row, index) => (
228
- <div key={index} class="mapka-popup-row">
229
- <dt class="mapka-popup-row-label">{row.name}</dt>
230
- <dd class="mapka-popup-row-value">{row.value != null ? String(row.value) : "—"}</dd>
231
- </div>
232
- ))}
233
- </dl>
59
+ {hasRows && <PopupDataRows rows={rows} />}
60
+
61
+ {primaryAction && (
62
+ <div class="mapka-popup-actions">
63
+ <PrimaryButton label={primaryAction.label} onClick={primaryAction.onClick} />
64
+ </div>
234
65
  )}
235
66
  </div>
236
67
  </div>
@@ -0,0 +1,41 @@
1
+ .mapka-popup-rows {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: 2px;
5
+ margin: 0;
6
+ width: 100%;
7
+ }
8
+
9
+ .mapka-popup-row {
10
+ display: flex;
11
+ flex-direction: row;
12
+ align-items: center;
13
+ gap: 16px;
14
+ height: 30px;
15
+ padding: 0 8px;
16
+ border-radius: 6px;
17
+ }
18
+
19
+ .mapka-popup-row-label {
20
+ flex: 1;
21
+ margin: 0;
22
+ font-weight: 400;
23
+ font-size: 12px;
24
+ line-height: 16px;
25
+ color: #4f4f4f;
26
+ }
27
+
28
+ .mapka-popup-row-value {
29
+ flex: 1;
30
+ margin: 0;
31
+ font-weight: 400;
32
+ font-size: 12px;
33
+ line-height: 16px;
34
+ color: #4f4f4f;
35
+ }
36
+
37
+ .mapka-popup-row-divider {
38
+ height: 0;
39
+ border-bottom: 1px solid #e0e0e0;
40
+ width: 100%;
41
+ }
@@ -0,0 +1,39 @@
1
+ import type { MapkaPopupRow } from "../types/popup.js";
2
+
3
+ export function displayRowValue(value: unknown) {
4
+ if (value == null) {
5
+ return "-";
6
+ }
7
+
8
+ if (typeof value === "number") {
9
+ return value.toLocaleString();
10
+ }
11
+ if (typeof value === "boolean") {
12
+ return value ? "true" : "false";
13
+ }
14
+ if (typeof value === "object") {
15
+ return JSON.stringify(value);
16
+ }
17
+
18
+ return value;
19
+ }
20
+
21
+ export function displayRowName(name: string) {
22
+ return name;
23
+ }
24
+
25
+ export function PopupDataRows({ rows }: { rows: MapkaPopupRow[] }) {
26
+ return (
27
+ <dl class="mapka-popup-rows">
28
+ {rows.map((row, index) => (
29
+ <>
30
+ {index > 0 && <div class="mapka-popup-row-divider" />}
31
+ <div key={index} class="mapka-popup-row">
32
+ <dt class="mapka-popup-row-label">{displayRowName(row.name)}</dt>
33
+ <dd class="mapka-popup-row-value">{displayRowValue(row.value)}</dd>
34
+ </div>
35
+ </>
36
+ ))}
37
+ </dl>
38
+ );
39
+ }
@@ -0,0 +1,24 @@
1
+ .mapka-popup-list-wrapper {
2
+ width: 100%;
3
+ overflow-y: auto;
4
+ }
5
+
6
+ .mapka-popup-list {
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: 8px;
10
+ overflow-y: auto;
11
+ max-height: 265px;
12
+ padding: 8px 8px 24px;
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ .mapka-popup-list-gradient {
17
+ position: absolute;
18
+ bottom: 0;
19
+ left: 0;
20
+ right: 0;
21
+ height: 54px;
22
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, #fff 100%);
23
+ pointer-events: none;
24
+ }
@@ -0,0 +1,27 @@
1
+ import type { MapkaPopupOptionsResolved } from "../types/popup.js";
2
+ import { PopupListItem } from "./PopupListItem.js";
3
+
4
+ interface PopupCollectionProps {
5
+ items: MapkaPopupOptionsResolved[];
6
+ }
7
+
8
+ export function PopupCustomElement({ popup }: { popup: HTMLElement }) {
9
+ return popup;
10
+ }
11
+
12
+ export function PopupList({ items }: PopupCollectionProps) {
13
+ return (
14
+ <div class="mapka-popup-list-wrapper">
15
+ <div class="mapka-popup-list">
16
+ {items.map(({ content, id }) =>
17
+ content instanceof HTMLElement ? (
18
+ <PopupCustomElement key={id} popup={content} />
19
+ ) : (
20
+ <PopupListItem key={id} popup={content} />
21
+ ),
22
+ )}
23
+ </div>
24
+ <div class="mapka-popup-list-gradient" />
25
+ </div>
26
+ );
27
+ }