@premiate/strapi-plugin-maplibre-field 1.2.0 → 1.2.2
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.
- package/CHANGELOG.md +49 -0
- package/dist/_chunks/{index-Dzpog-Qf.mjs → index-B0Nr95wz.mjs} +2 -2
- package/dist/_chunks/{index-Bp7DLorc.mjs → index-CBxydRKp.mjs} +1 -1
- package/dist/_chunks/{index-zNvHsRuo.js → index-CDY4Awnh.js} +1 -1
- package/dist/_chunks/{index-DjK7O741.js → index-ysvid6md.js} +2 -2
- package/dist/admin/de-B0QBc7M2.js +27 -0
- package/dist/admin/de-BMK0skCB.mjs +27 -0
- package/dist/admin/en-C8iInpNv.mjs +27 -0
- package/dist/admin/en-CA0XtbN7.js +27 -0
- package/dist/admin/es-BU6JgkbZ.js +25 -0
- package/dist/admin/es-DZO4NHjt.mjs +25 -0
- package/dist/admin/fr-B8NDboqe.mjs +27 -0
- package/dist/admin/fr-DIBfzRbg.js +27 -0
- package/dist/admin/index-B-3vqPUe.mjs +1836 -0
- package/dist/admin/index-B0LVK-NK.js +170 -0
- package/dist/admin/index-BaGweGhM.js +1856 -0
- package/dist/admin/index-DjL4deZ6.mjs +171 -0
- package/dist/admin/index.js +3 -2
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/it-B-lr3jhh.js +27 -0
- package/dist/admin/it-DFH6n6E1.mjs +27 -0
- package/dist/server/index.js +8 -3
- package/dist/server/index.mjs +6 -2
- package/dist/server/src/index.d.ts +9 -4
- package/package.json +12 -9
- package/dist/admin/src/components/Initializer.d.ts +0 -6
- package/dist/admin/src/components/MapInput/SearchBox.d.ts +0 -22
- package/dist/admin/src/components/MapInput/basemap-control.d.ts +0 -8
- package/dist/admin/src/components/MapInput/index.d.ts +0 -19
- package/dist/admin/src/components/MapInput/layer-control.d.ts +0 -18
- package/dist/admin/src/components/PluginIcon.d.ts +0 -2
- package/dist/admin/src/hooks/usePluginConfig.d.ts +0 -2
- package/dist/admin/src/mutations/mutateEditViewHook.d.ts +0 -30
- package/dist/admin/src/services/geocoder-service.d.ts +0 -31
- package/dist/admin/src/services/poi-service.d.ts +0 -160
- package/dist/admin/src/utils/getTrad.d.ts +0 -2
- package/dist/admin/src/utils/pluginId.d.ts +0 -2
- package/dist/admin/src/utils/prefixPluginTranslations.d.ts +0 -3
- package/dist/server/src/bootstrap.d.ts +0 -2
- package/dist/server/src/config/index.d.ts +0 -62
- package/dist/server/src/config/schema.d.ts +0 -53
- package/dist/server/src/controllers/config.d.ts +0 -9
- package/dist/server/src/controllers/index.d.ts +0 -10
- package/dist/server/src/destroy.d.ts +0 -2
- package/dist/server/src/register.d.ts +0 -5
- package/dist/server/src/routes/admin.d.ts +0 -12
- package/dist/server/src/routes/index.d.ts +0 -14
- package/dist/server/src/types/config.d.ts +0 -26
|
@@ -0,0 +1,1856 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const React = require("react");
|
|
5
|
+
const admin = require("@strapi/strapi/admin");
|
|
6
|
+
const designSystem = require("@strapi/design-system");
|
|
7
|
+
const index = require("./index-B0LVK-NK.js");
|
|
8
|
+
const Map = require("react-map-gl/maplibre");
|
|
9
|
+
const pmtiles = require("pmtiles");
|
|
10
|
+
const maplibregl = require("maplibre-gl");
|
|
11
|
+
require("maplibre-gl/dist/maplibre-gl.css");
|
|
12
|
+
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
13
|
+
function _interopNamespace(e) {
|
|
14
|
+
if (e && e.__esModule) return e;
|
|
15
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
16
|
+
if (e) {
|
|
17
|
+
for (const k in e) {
|
|
18
|
+
if (k !== "default") {
|
|
19
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
20
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: () => e[k]
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
n.default = e;
|
|
28
|
+
return Object.freeze(n);
|
|
29
|
+
}
|
|
30
|
+
const React__namespace = /* @__PURE__ */ _interopNamespace(React);
|
|
31
|
+
const Map__default = /* @__PURE__ */ _interopDefault(Map);
|
|
32
|
+
const maplibregl__default = /* @__PURE__ */ _interopDefault(maplibregl);
|
|
33
|
+
var __assign = function() {
|
|
34
|
+
__assign = Object.assign || function __assign2(t) {
|
|
35
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
36
|
+
s = arguments[i];
|
|
37
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
|
38
|
+
}
|
|
39
|
+
return t;
|
|
40
|
+
};
|
|
41
|
+
return __assign.apply(this, arguments);
|
|
42
|
+
};
|
|
43
|
+
function __rest(s, e) {
|
|
44
|
+
var t = {};
|
|
45
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
46
|
+
t[p] = s[p];
|
|
47
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
48
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
49
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
50
|
+
t[p[i]] = s[p[i]];
|
|
51
|
+
}
|
|
52
|
+
return t;
|
|
53
|
+
}
|
|
54
|
+
typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
|
|
55
|
+
var e = new Error(message);
|
|
56
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
57
|
+
};
|
|
58
|
+
var reactIs = { exports: {} };
|
|
59
|
+
var reactIs_production_min = {};
|
|
60
|
+
/** @license React v16.13.1
|
|
61
|
+
* react-is.production.min.js
|
|
62
|
+
*
|
|
63
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
64
|
+
*
|
|
65
|
+
* This source code is licensed under the MIT license found in the
|
|
66
|
+
* LICENSE file in the root directory of this source tree.
|
|
67
|
+
*/
|
|
68
|
+
var hasRequiredReactIs_production_min;
|
|
69
|
+
function requireReactIs_production_min() {
|
|
70
|
+
if (hasRequiredReactIs_production_min) return reactIs_production_min;
|
|
71
|
+
hasRequiredReactIs_production_min = 1;
|
|
72
|
+
var b = "function" === typeof Symbol && Symbol.for, c = b ? Symbol.for("react.element") : 60103, d = b ? Symbol.for("react.portal") : 60106, e = b ? Symbol.for("react.fragment") : 60107, f = b ? Symbol.for("react.strict_mode") : 60108, g = b ? Symbol.for("react.profiler") : 60114, h = b ? Symbol.for("react.provider") : 60109, k = b ? Symbol.for("react.context") : 60110, l = b ? Symbol.for("react.async_mode") : 60111, m = b ? Symbol.for("react.concurrent_mode") : 60111, n = b ? Symbol.for("react.forward_ref") : 60112, p = b ? Symbol.for("react.suspense") : 60113, q = b ? Symbol.for("react.suspense_list") : 60120, r = b ? Symbol.for("react.memo") : 60115, t = b ? Symbol.for("react.lazy") : 60116, v = b ? Symbol.for("react.block") : 60121, w = b ? Symbol.for("react.fundamental") : 60117, x = b ? Symbol.for("react.responder") : 60118, y = b ? Symbol.for("react.scope") : 60119;
|
|
73
|
+
function z(a) {
|
|
74
|
+
if ("object" === typeof a && null !== a) {
|
|
75
|
+
var u = a.$$typeof;
|
|
76
|
+
switch (u) {
|
|
77
|
+
case c:
|
|
78
|
+
switch (a = a.type, a) {
|
|
79
|
+
case l:
|
|
80
|
+
case m:
|
|
81
|
+
case e:
|
|
82
|
+
case g:
|
|
83
|
+
case f:
|
|
84
|
+
case p:
|
|
85
|
+
return a;
|
|
86
|
+
default:
|
|
87
|
+
switch (a = a && a.$$typeof, a) {
|
|
88
|
+
case k:
|
|
89
|
+
case n:
|
|
90
|
+
case t:
|
|
91
|
+
case r:
|
|
92
|
+
case h:
|
|
93
|
+
return a;
|
|
94
|
+
default:
|
|
95
|
+
return u;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
case d:
|
|
99
|
+
return u;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function A(a) {
|
|
104
|
+
return z(a) === m;
|
|
105
|
+
}
|
|
106
|
+
reactIs_production_min.AsyncMode = l;
|
|
107
|
+
reactIs_production_min.ConcurrentMode = m;
|
|
108
|
+
reactIs_production_min.ContextConsumer = k;
|
|
109
|
+
reactIs_production_min.ContextProvider = h;
|
|
110
|
+
reactIs_production_min.Element = c;
|
|
111
|
+
reactIs_production_min.ForwardRef = n;
|
|
112
|
+
reactIs_production_min.Fragment = e;
|
|
113
|
+
reactIs_production_min.Lazy = t;
|
|
114
|
+
reactIs_production_min.Memo = r;
|
|
115
|
+
reactIs_production_min.Portal = d;
|
|
116
|
+
reactIs_production_min.Profiler = g;
|
|
117
|
+
reactIs_production_min.StrictMode = f;
|
|
118
|
+
reactIs_production_min.Suspense = p;
|
|
119
|
+
reactIs_production_min.isAsyncMode = function(a) {
|
|
120
|
+
return A(a) || z(a) === l;
|
|
121
|
+
};
|
|
122
|
+
reactIs_production_min.isConcurrentMode = A;
|
|
123
|
+
reactIs_production_min.isContextConsumer = function(a) {
|
|
124
|
+
return z(a) === k;
|
|
125
|
+
};
|
|
126
|
+
reactIs_production_min.isContextProvider = function(a) {
|
|
127
|
+
return z(a) === h;
|
|
128
|
+
};
|
|
129
|
+
reactIs_production_min.isElement = function(a) {
|
|
130
|
+
return "object" === typeof a && null !== a && a.$$typeof === c;
|
|
131
|
+
};
|
|
132
|
+
reactIs_production_min.isForwardRef = function(a) {
|
|
133
|
+
return z(a) === n;
|
|
134
|
+
};
|
|
135
|
+
reactIs_production_min.isFragment = function(a) {
|
|
136
|
+
return z(a) === e;
|
|
137
|
+
};
|
|
138
|
+
reactIs_production_min.isLazy = function(a) {
|
|
139
|
+
return z(a) === t;
|
|
140
|
+
};
|
|
141
|
+
reactIs_production_min.isMemo = function(a) {
|
|
142
|
+
return z(a) === r;
|
|
143
|
+
};
|
|
144
|
+
reactIs_production_min.isPortal = function(a) {
|
|
145
|
+
return z(a) === d;
|
|
146
|
+
};
|
|
147
|
+
reactIs_production_min.isProfiler = function(a) {
|
|
148
|
+
return z(a) === g;
|
|
149
|
+
};
|
|
150
|
+
reactIs_production_min.isStrictMode = function(a) {
|
|
151
|
+
return z(a) === f;
|
|
152
|
+
};
|
|
153
|
+
reactIs_production_min.isSuspense = function(a) {
|
|
154
|
+
return z(a) === p;
|
|
155
|
+
};
|
|
156
|
+
reactIs_production_min.isValidElementType = function(a) {
|
|
157
|
+
return "string" === typeof a || "function" === typeof a || a === e || a === m || a === g || a === f || a === p || a === q || "object" === typeof a && null !== a && (a.$$typeof === t || a.$$typeof === r || a.$$typeof === h || a.$$typeof === k || a.$$typeof === n || a.$$typeof === w || a.$$typeof === x || a.$$typeof === y || a.$$typeof === v);
|
|
158
|
+
};
|
|
159
|
+
reactIs_production_min.typeOf = z;
|
|
160
|
+
return reactIs_production_min;
|
|
161
|
+
}
|
|
162
|
+
var reactIs_development = {};
|
|
163
|
+
/** @license React v16.13.1
|
|
164
|
+
* react-is.development.js
|
|
165
|
+
*
|
|
166
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
167
|
+
*
|
|
168
|
+
* This source code is licensed under the MIT license found in the
|
|
169
|
+
* LICENSE file in the root directory of this source tree.
|
|
170
|
+
*/
|
|
171
|
+
var hasRequiredReactIs_development;
|
|
172
|
+
function requireReactIs_development() {
|
|
173
|
+
if (hasRequiredReactIs_development) return reactIs_development;
|
|
174
|
+
hasRequiredReactIs_development = 1;
|
|
175
|
+
if (process.env.NODE_ENV !== "production") {
|
|
176
|
+
(function() {
|
|
177
|
+
var hasSymbol = typeof Symbol === "function" && Symbol.for;
|
|
178
|
+
var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103;
|
|
179
|
+
var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106;
|
|
180
|
+
var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107;
|
|
181
|
+
var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for("react.strict_mode") : 60108;
|
|
182
|
+
var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 60114;
|
|
183
|
+
var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 60109;
|
|
184
|
+
var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 60110;
|
|
185
|
+
var REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol.for("react.async_mode") : 60111;
|
|
186
|
+
var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for("react.concurrent_mode") : 60111;
|
|
187
|
+
var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for("react.forward_ref") : 60112;
|
|
188
|
+
var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 60113;
|
|
189
|
+
var REACT_SUSPENSE_LIST_TYPE = hasSymbol ? Symbol.for("react.suspense_list") : 60120;
|
|
190
|
+
var REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 60115;
|
|
191
|
+
var REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 60116;
|
|
192
|
+
var REACT_BLOCK_TYPE = hasSymbol ? Symbol.for("react.block") : 60121;
|
|
193
|
+
var REACT_FUNDAMENTAL_TYPE = hasSymbol ? Symbol.for("react.fundamental") : 60117;
|
|
194
|
+
var REACT_RESPONDER_TYPE = hasSymbol ? Symbol.for("react.responder") : 60118;
|
|
195
|
+
var REACT_SCOPE_TYPE = hasSymbol ? Symbol.for("react.scope") : 60119;
|
|
196
|
+
function isValidElementType(type) {
|
|
197
|
+
return typeof type === "string" || typeof type === "function" || // Note: its typeof might be other than 'symbol' or 'number' if it's a polyfill.
|
|
198
|
+
type === REACT_FRAGMENT_TYPE || type === REACT_CONCURRENT_MODE_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || typeof type === "object" && type !== null && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_RESPONDER_TYPE || type.$$typeof === REACT_SCOPE_TYPE || type.$$typeof === REACT_BLOCK_TYPE);
|
|
199
|
+
}
|
|
200
|
+
function typeOf(object) {
|
|
201
|
+
if (typeof object === "object" && object !== null) {
|
|
202
|
+
var $$typeof = object.$$typeof;
|
|
203
|
+
switch ($$typeof) {
|
|
204
|
+
case REACT_ELEMENT_TYPE:
|
|
205
|
+
var type = object.type;
|
|
206
|
+
switch (type) {
|
|
207
|
+
case REACT_ASYNC_MODE_TYPE:
|
|
208
|
+
case REACT_CONCURRENT_MODE_TYPE:
|
|
209
|
+
case REACT_FRAGMENT_TYPE:
|
|
210
|
+
case REACT_PROFILER_TYPE:
|
|
211
|
+
case REACT_STRICT_MODE_TYPE:
|
|
212
|
+
case REACT_SUSPENSE_TYPE:
|
|
213
|
+
return type;
|
|
214
|
+
default:
|
|
215
|
+
var $$typeofType = type && type.$$typeof;
|
|
216
|
+
switch ($$typeofType) {
|
|
217
|
+
case REACT_CONTEXT_TYPE:
|
|
218
|
+
case REACT_FORWARD_REF_TYPE:
|
|
219
|
+
case REACT_LAZY_TYPE:
|
|
220
|
+
case REACT_MEMO_TYPE:
|
|
221
|
+
case REACT_PROVIDER_TYPE:
|
|
222
|
+
return $$typeofType;
|
|
223
|
+
default:
|
|
224
|
+
return $$typeof;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
case REACT_PORTAL_TYPE:
|
|
228
|
+
return $$typeof;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return void 0;
|
|
232
|
+
}
|
|
233
|
+
var AsyncMode = REACT_ASYNC_MODE_TYPE;
|
|
234
|
+
var ConcurrentMode = REACT_CONCURRENT_MODE_TYPE;
|
|
235
|
+
var ContextConsumer = REACT_CONTEXT_TYPE;
|
|
236
|
+
var ContextProvider = REACT_PROVIDER_TYPE;
|
|
237
|
+
var Element = REACT_ELEMENT_TYPE;
|
|
238
|
+
var ForwardRef = REACT_FORWARD_REF_TYPE;
|
|
239
|
+
var Fragment = REACT_FRAGMENT_TYPE;
|
|
240
|
+
var Lazy = REACT_LAZY_TYPE;
|
|
241
|
+
var Memo = REACT_MEMO_TYPE;
|
|
242
|
+
var Portal = REACT_PORTAL_TYPE;
|
|
243
|
+
var Profiler = REACT_PROFILER_TYPE;
|
|
244
|
+
var StrictMode = REACT_STRICT_MODE_TYPE;
|
|
245
|
+
var Suspense = REACT_SUSPENSE_TYPE;
|
|
246
|
+
var hasWarnedAboutDeprecatedIsAsyncMode = false;
|
|
247
|
+
function isAsyncMode(object) {
|
|
248
|
+
{
|
|
249
|
+
if (!hasWarnedAboutDeprecatedIsAsyncMode) {
|
|
250
|
+
hasWarnedAboutDeprecatedIsAsyncMode = true;
|
|
251
|
+
console["warn"]("The ReactIs.isAsyncMode() alias has been deprecated, and will be removed in React 17+. Update your code to use ReactIs.isConcurrentMode() instead. It has the exact same API.");
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return isConcurrentMode(object) || typeOf(object) === REACT_ASYNC_MODE_TYPE;
|
|
255
|
+
}
|
|
256
|
+
function isConcurrentMode(object) {
|
|
257
|
+
return typeOf(object) === REACT_CONCURRENT_MODE_TYPE;
|
|
258
|
+
}
|
|
259
|
+
function isContextConsumer(object) {
|
|
260
|
+
return typeOf(object) === REACT_CONTEXT_TYPE;
|
|
261
|
+
}
|
|
262
|
+
function isContextProvider(object) {
|
|
263
|
+
return typeOf(object) === REACT_PROVIDER_TYPE;
|
|
264
|
+
}
|
|
265
|
+
function isElement(object) {
|
|
266
|
+
return typeof object === "object" && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
|
|
267
|
+
}
|
|
268
|
+
function isForwardRef(object) {
|
|
269
|
+
return typeOf(object) === REACT_FORWARD_REF_TYPE;
|
|
270
|
+
}
|
|
271
|
+
function isFragment(object) {
|
|
272
|
+
return typeOf(object) === REACT_FRAGMENT_TYPE;
|
|
273
|
+
}
|
|
274
|
+
function isLazy(object) {
|
|
275
|
+
return typeOf(object) === REACT_LAZY_TYPE;
|
|
276
|
+
}
|
|
277
|
+
function isMemo(object) {
|
|
278
|
+
return typeOf(object) === REACT_MEMO_TYPE;
|
|
279
|
+
}
|
|
280
|
+
function isPortal(object) {
|
|
281
|
+
return typeOf(object) === REACT_PORTAL_TYPE;
|
|
282
|
+
}
|
|
283
|
+
function isProfiler(object) {
|
|
284
|
+
return typeOf(object) === REACT_PROFILER_TYPE;
|
|
285
|
+
}
|
|
286
|
+
function isStrictMode(object) {
|
|
287
|
+
return typeOf(object) === REACT_STRICT_MODE_TYPE;
|
|
288
|
+
}
|
|
289
|
+
function isSuspense(object) {
|
|
290
|
+
return typeOf(object) === REACT_SUSPENSE_TYPE;
|
|
291
|
+
}
|
|
292
|
+
reactIs_development.AsyncMode = AsyncMode;
|
|
293
|
+
reactIs_development.ConcurrentMode = ConcurrentMode;
|
|
294
|
+
reactIs_development.ContextConsumer = ContextConsumer;
|
|
295
|
+
reactIs_development.ContextProvider = ContextProvider;
|
|
296
|
+
reactIs_development.Element = Element;
|
|
297
|
+
reactIs_development.ForwardRef = ForwardRef;
|
|
298
|
+
reactIs_development.Fragment = Fragment;
|
|
299
|
+
reactIs_development.Lazy = Lazy;
|
|
300
|
+
reactIs_development.Memo = Memo;
|
|
301
|
+
reactIs_development.Portal = Portal;
|
|
302
|
+
reactIs_development.Profiler = Profiler;
|
|
303
|
+
reactIs_development.StrictMode = StrictMode;
|
|
304
|
+
reactIs_development.Suspense = Suspense;
|
|
305
|
+
reactIs_development.isAsyncMode = isAsyncMode;
|
|
306
|
+
reactIs_development.isConcurrentMode = isConcurrentMode;
|
|
307
|
+
reactIs_development.isContextConsumer = isContextConsumer;
|
|
308
|
+
reactIs_development.isContextProvider = isContextProvider;
|
|
309
|
+
reactIs_development.isElement = isElement;
|
|
310
|
+
reactIs_development.isForwardRef = isForwardRef;
|
|
311
|
+
reactIs_development.isFragment = isFragment;
|
|
312
|
+
reactIs_development.isLazy = isLazy;
|
|
313
|
+
reactIs_development.isMemo = isMemo;
|
|
314
|
+
reactIs_development.isPortal = isPortal;
|
|
315
|
+
reactIs_development.isProfiler = isProfiler;
|
|
316
|
+
reactIs_development.isStrictMode = isStrictMode;
|
|
317
|
+
reactIs_development.isSuspense = isSuspense;
|
|
318
|
+
reactIs_development.isValidElementType = isValidElementType;
|
|
319
|
+
reactIs_development.typeOf = typeOf;
|
|
320
|
+
})();
|
|
321
|
+
}
|
|
322
|
+
return reactIs_development;
|
|
323
|
+
}
|
|
324
|
+
var hasRequiredReactIs;
|
|
325
|
+
function requireReactIs() {
|
|
326
|
+
if (hasRequiredReactIs) return reactIs.exports;
|
|
327
|
+
hasRequiredReactIs = 1;
|
|
328
|
+
if (process.env.NODE_ENV === "production") {
|
|
329
|
+
reactIs.exports = requireReactIs_production_min();
|
|
330
|
+
} else {
|
|
331
|
+
reactIs.exports = requireReactIs_development();
|
|
332
|
+
}
|
|
333
|
+
return reactIs.exports;
|
|
334
|
+
}
|
|
335
|
+
var hoistNonReactStatics_cjs;
|
|
336
|
+
var hasRequiredHoistNonReactStatics_cjs;
|
|
337
|
+
function requireHoistNonReactStatics_cjs() {
|
|
338
|
+
if (hasRequiredHoistNonReactStatics_cjs) return hoistNonReactStatics_cjs;
|
|
339
|
+
hasRequiredHoistNonReactStatics_cjs = 1;
|
|
340
|
+
var reactIs2 = requireReactIs();
|
|
341
|
+
var REACT_STATICS = {
|
|
342
|
+
childContextTypes: true,
|
|
343
|
+
contextType: true,
|
|
344
|
+
contextTypes: true,
|
|
345
|
+
defaultProps: true,
|
|
346
|
+
displayName: true,
|
|
347
|
+
getDefaultProps: true,
|
|
348
|
+
getDerivedStateFromError: true,
|
|
349
|
+
getDerivedStateFromProps: true,
|
|
350
|
+
mixins: true,
|
|
351
|
+
propTypes: true,
|
|
352
|
+
type: true
|
|
353
|
+
};
|
|
354
|
+
var KNOWN_STATICS = {
|
|
355
|
+
name: true,
|
|
356
|
+
length: true,
|
|
357
|
+
prototype: true,
|
|
358
|
+
caller: true,
|
|
359
|
+
callee: true,
|
|
360
|
+
arguments: true,
|
|
361
|
+
arity: true
|
|
362
|
+
};
|
|
363
|
+
var FORWARD_REF_STATICS = {
|
|
364
|
+
"$$typeof": true,
|
|
365
|
+
render: true,
|
|
366
|
+
defaultProps: true,
|
|
367
|
+
displayName: true,
|
|
368
|
+
propTypes: true
|
|
369
|
+
};
|
|
370
|
+
var MEMO_STATICS = {
|
|
371
|
+
"$$typeof": true,
|
|
372
|
+
compare: true,
|
|
373
|
+
defaultProps: true,
|
|
374
|
+
displayName: true,
|
|
375
|
+
propTypes: true,
|
|
376
|
+
type: true
|
|
377
|
+
};
|
|
378
|
+
var TYPE_STATICS = {};
|
|
379
|
+
TYPE_STATICS[reactIs2.ForwardRef] = FORWARD_REF_STATICS;
|
|
380
|
+
TYPE_STATICS[reactIs2.Memo] = MEMO_STATICS;
|
|
381
|
+
function getStatics(component) {
|
|
382
|
+
if (reactIs2.isMemo(component)) {
|
|
383
|
+
return MEMO_STATICS;
|
|
384
|
+
}
|
|
385
|
+
return TYPE_STATICS[component["$$typeof"]] || REACT_STATICS;
|
|
386
|
+
}
|
|
387
|
+
var defineProperty = Object.defineProperty;
|
|
388
|
+
var getOwnPropertyNames = Object.getOwnPropertyNames;
|
|
389
|
+
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
|
|
390
|
+
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
|
391
|
+
var getPrototypeOf = Object.getPrototypeOf;
|
|
392
|
+
var objectPrototype = Object.prototype;
|
|
393
|
+
function hoistNonReactStatics(targetComponent, sourceComponent, blacklist) {
|
|
394
|
+
if (typeof sourceComponent !== "string") {
|
|
395
|
+
if (objectPrototype) {
|
|
396
|
+
var inheritedComponent = getPrototypeOf(sourceComponent);
|
|
397
|
+
if (inheritedComponent && inheritedComponent !== objectPrototype) {
|
|
398
|
+
hoistNonReactStatics(targetComponent, inheritedComponent, blacklist);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
var keys = getOwnPropertyNames(sourceComponent);
|
|
402
|
+
if (getOwnPropertySymbols) {
|
|
403
|
+
keys = keys.concat(getOwnPropertySymbols(sourceComponent));
|
|
404
|
+
}
|
|
405
|
+
var targetStatics = getStatics(targetComponent);
|
|
406
|
+
var sourceStatics = getStatics(sourceComponent);
|
|
407
|
+
for (var i = 0; i < keys.length; ++i) {
|
|
408
|
+
var key = keys[i];
|
|
409
|
+
if (!KNOWN_STATICS[key] && !(blacklist && blacklist[key]) && !(sourceStatics && sourceStatics[key]) && !(targetStatics && targetStatics[key])) {
|
|
410
|
+
var descriptor = getOwnPropertyDescriptor(sourceComponent, key);
|
|
411
|
+
try {
|
|
412
|
+
defineProperty(targetComponent, key, descriptor);
|
|
413
|
+
} catch (e) {
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return targetComponent;
|
|
419
|
+
}
|
|
420
|
+
hoistNonReactStatics_cjs = hoistNonReactStatics;
|
|
421
|
+
return hoistNonReactStatics_cjs;
|
|
422
|
+
}
|
|
423
|
+
requireHoistNonReactStatics_cjs();
|
|
424
|
+
function invariant(condition, message, Err) {
|
|
425
|
+
if (Err === void 0) {
|
|
426
|
+
Err = Error;
|
|
427
|
+
}
|
|
428
|
+
if (!condition) {
|
|
429
|
+
throw new Err(message);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
var defaultErrorHandler = function(error) {
|
|
433
|
+
if (process.env.NODE_ENV !== "production") {
|
|
434
|
+
console.error(error);
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
var defaultWarnHandler = function(warning) {
|
|
438
|
+
if (process.env.NODE_ENV !== "production") {
|
|
439
|
+
console.warn(warning);
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
var DEFAULT_INTL_CONFIG = {
|
|
443
|
+
formats: {},
|
|
444
|
+
messages: {},
|
|
445
|
+
timeZone: void 0,
|
|
446
|
+
defaultLocale: "en",
|
|
447
|
+
defaultFormats: {},
|
|
448
|
+
fallbackOnEmptyString: true,
|
|
449
|
+
onError: defaultErrorHandler,
|
|
450
|
+
onWarn: defaultWarnHandler
|
|
451
|
+
};
|
|
452
|
+
function invariantIntlContext(intl) {
|
|
453
|
+
invariant(intl, "[React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.");
|
|
454
|
+
}
|
|
455
|
+
__assign(__assign({}, DEFAULT_INTL_CONFIG), { textComponent: React__namespace.Fragment });
|
|
456
|
+
var IntlContext = typeof window !== "undefined" && !window.__REACT_INTL_BYPASS_GLOBAL_CONTEXT__ ? window.__REACT_INTL_CONTEXT__ || (window.__REACT_INTL_CONTEXT__ = React__namespace.createContext(null)) : React__namespace.createContext(null);
|
|
457
|
+
IntlContext.Consumer;
|
|
458
|
+
IntlContext.Provider;
|
|
459
|
+
var Context = IntlContext;
|
|
460
|
+
function useIntl() {
|
|
461
|
+
var intl = React__namespace.useContext(Context);
|
|
462
|
+
invariantIntlContext(intl);
|
|
463
|
+
return intl;
|
|
464
|
+
}
|
|
465
|
+
var DisplayName;
|
|
466
|
+
(function(DisplayName2) {
|
|
467
|
+
DisplayName2["formatDate"] = "FormattedDate";
|
|
468
|
+
DisplayName2["formatTime"] = "FormattedTime";
|
|
469
|
+
DisplayName2["formatNumber"] = "FormattedNumber";
|
|
470
|
+
DisplayName2["formatList"] = "FormattedList";
|
|
471
|
+
DisplayName2["formatDisplayName"] = "FormattedDisplayName";
|
|
472
|
+
})(DisplayName || (DisplayName = {}));
|
|
473
|
+
var DisplayNameParts;
|
|
474
|
+
(function(DisplayNameParts2) {
|
|
475
|
+
DisplayNameParts2["formatDate"] = "FormattedDateParts";
|
|
476
|
+
DisplayNameParts2["formatTime"] = "FormattedTimeParts";
|
|
477
|
+
DisplayNameParts2["formatNumber"] = "FormattedNumberParts";
|
|
478
|
+
DisplayNameParts2["formatList"] = "FormattedListParts";
|
|
479
|
+
})(DisplayNameParts || (DisplayNameParts = {}));
|
|
480
|
+
function createFormattedDateTimePartsComponent(name) {
|
|
481
|
+
var ComponentParts = function(props) {
|
|
482
|
+
var intl = useIntl();
|
|
483
|
+
var value = props.value, children = props.children, formatProps = __rest(props, ["value", "children"]);
|
|
484
|
+
var date = typeof value === "string" ? new Date(value || 0) : value;
|
|
485
|
+
var formattedParts = name === "formatDate" ? intl.formatDateToParts(date, formatProps) : intl.formatTimeToParts(date, formatProps);
|
|
486
|
+
return children(formattedParts);
|
|
487
|
+
};
|
|
488
|
+
ComponentParts.displayName = DisplayNameParts[name];
|
|
489
|
+
return ComponentParts;
|
|
490
|
+
}
|
|
491
|
+
function createFormattedComponent(name) {
|
|
492
|
+
var Component = function(props) {
|
|
493
|
+
var intl = useIntl();
|
|
494
|
+
var value = props.value, children = props.children, formatProps = __rest(
|
|
495
|
+
props,
|
|
496
|
+
["value", "children"]
|
|
497
|
+
);
|
|
498
|
+
var formattedValue = intl[name](value, formatProps);
|
|
499
|
+
if (typeof children === "function") {
|
|
500
|
+
return children(formattedValue);
|
|
501
|
+
}
|
|
502
|
+
var Text = intl.textComponent || React__namespace.Fragment;
|
|
503
|
+
return React__namespace.createElement(Text, null, formattedValue);
|
|
504
|
+
};
|
|
505
|
+
Component.displayName = DisplayName[name];
|
|
506
|
+
return Component;
|
|
507
|
+
}
|
|
508
|
+
createFormattedComponent("formatDate");
|
|
509
|
+
createFormattedComponent("formatTime");
|
|
510
|
+
createFormattedComponent("formatNumber");
|
|
511
|
+
createFormattedComponent("formatList");
|
|
512
|
+
createFormattedComponent("formatDisplayName");
|
|
513
|
+
createFormattedDateTimePartsComponent("formatDate");
|
|
514
|
+
createFormattedDateTimePartsComponent("formatTime");
|
|
515
|
+
const USER_AGENT$1 = "strapi-plugin-maplibre-field (Strapi CMS)";
|
|
516
|
+
function createLocationFeature(coordinates, properties = {}) {
|
|
517
|
+
const cleanProperties = Object.fromEntries(
|
|
518
|
+
Object.entries(properties).filter(([, v]) => v != null && v !== "")
|
|
519
|
+
);
|
|
520
|
+
return {
|
|
521
|
+
type: "Feature",
|
|
522
|
+
geometry: {
|
|
523
|
+
type: "Point",
|
|
524
|
+
coordinates
|
|
525
|
+
},
|
|
526
|
+
properties: cleanProperties
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
function calculateDistance(coord1, coord2) {
|
|
530
|
+
const R = 6371e3;
|
|
531
|
+
const φ1 = coord1[1] * Math.PI / 180;
|
|
532
|
+
const φ2 = coord2[1] * Math.PI / 180;
|
|
533
|
+
const Δφ = (coord2[1] - coord1[1]) * Math.PI / 180;
|
|
534
|
+
const Δλ = (coord2[0] - coord1[0]) * Math.PI / 180;
|
|
535
|
+
const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) + Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
|
|
536
|
+
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
537
|
+
return R * c;
|
|
538
|
+
}
|
|
539
|
+
async function queryCustomAPI(apiUrl, searchQuery) {
|
|
540
|
+
try {
|
|
541
|
+
const response = await fetch(apiUrl);
|
|
542
|
+
if (!response.ok) {
|
|
543
|
+
console.error(
|
|
544
|
+
`[POI Service] HTTP error for ${apiUrl}: ${response.status} ${response.statusText}`
|
|
545
|
+
);
|
|
546
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
547
|
+
}
|
|
548
|
+
const data = await response.json();
|
|
549
|
+
if (!data || data.type !== "FeatureCollection" || !Array.isArray(data.features)) {
|
|
550
|
+
console.error(`[POI Service] Invalid GeoJSON from ${apiUrl}`);
|
|
551
|
+
throw new Error("Invalid GeoJSON response format");
|
|
552
|
+
}
|
|
553
|
+
let features = data.features;
|
|
554
|
+
if (searchQuery && searchQuery.trim()) {
|
|
555
|
+
const query = searchQuery.toLowerCase();
|
|
556
|
+
features = features.filter((feature) => {
|
|
557
|
+
const name = feature.properties?.name;
|
|
558
|
+
return name && name.toLowerCase().includes(query);
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
return features;
|
|
562
|
+
} catch (error) {
|
|
563
|
+
console.error(`[POI Service] Failed to load from ${apiUrl}:`, error);
|
|
564
|
+
return [];
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
async function queryNominatim(lat, lng, radius, nominatimUrl) {
|
|
568
|
+
try {
|
|
569
|
+
const url = `${nominatimUrl}/reverse?format=jsonv2&lat=${lat}&lon=${lng}&zoom=18&addressdetails=1`;
|
|
570
|
+
const response = await fetch(url, {
|
|
571
|
+
headers: {
|
|
572
|
+
"User-Agent": USER_AGENT$1
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
if (!response.ok) {
|
|
576
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
577
|
+
}
|
|
578
|
+
const data = await response.json();
|
|
579
|
+
if (!data) {
|
|
580
|
+
return [];
|
|
581
|
+
}
|
|
582
|
+
const coordinates = [parseFloat(data.lon), parseFloat(data.lat)];
|
|
583
|
+
const distance = calculateDistance([lng, lat], coordinates);
|
|
584
|
+
if (distance > radius) {
|
|
585
|
+
return [];
|
|
586
|
+
}
|
|
587
|
+
let poiName = data.name || data.display_name || "Unknown Location";
|
|
588
|
+
if (data.namedetails) {
|
|
589
|
+
poiName = data.namedetails.name || poiName;
|
|
590
|
+
}
|
|
591
|
+
const poi = {
|
|
592
|
+
id: `nominatim-${data.place_id || Date.now()}`,
|
|
593
|
+
name: poiName,
|
|
594
|
+
type: data.type || data.class || "address",
|
|
595
|
+
coordinates,
|
|
596
|
+
address: data.display_name || "",
|
|
597
|
+
distance,
|
|
598
|
+
metadata: {
|
|
599
|
+
osm_id: data.osm_id,
|
|
600
|
+
osm_type: data.osm_type,
|
|
601
|
+
place_id: data.place_id,
|
|
602
|
+
addresstype: data.addresstype,
|
|
603
|
+
class: data.class,
|
|
604
|
+
category: data.category
|
|
605
|
+
},
|
|
606
|
+
source: "nominatim"
|
|
607
|
+
};
|
|
608
|
+
return [poi];
|
|
609
|
+
} catch (error) {
|
|
610
|
+
console.error("Nominatim query error:", error);
|
|
611
|
+
return [];
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
function geoJSONFeatureToPOI(feature, clickCoords, mapName, layerId) {
|
|
615
|
+
if (!feature.geometry || feature.geometry.type !== "Point") {
|
|
616
|
+
return null;
|
|
617
|
+
}
|
|
618
|
+
const coordinates = feature.geometry.coordinates;
|
|
619
|
+
const properties = feature.properties || {};
|
|
620
|
+
const getString = (val) => typeof val === "string" ? val : void 0;
|
|
621
|
+
const name = getString(properties.name) || "Unnamed Location";
|
|
622
|
+
const poi = {
|
|
623
|
+
id: feature.id?.toString() || `custom-${Date.now()}-${Math.random()}`,
|
|
624
|
+
name,
|
|
625
|
+
type: getString(properties.type) || getString(properties.sport) || getString(properties.leisure) || "poi",
|
|
626
|
+
coordinates,
|
|
627
|
+
address: getString(properties.address) || "",
|
|
628
|
+
// Leave empty if not provided
|
|
629
|
+
metadata: properties,
|
|
630
|
+
source: "custom",
|
|
631
|
+
mapName,
|
|
632
|
+
// Include the custom map name
|
|
633
|
+
layerId
|
|
634
|
+
// Include the layer ID
|
|
635
|
+
};
|
|
636
|
+
if (clickCoords) {
|
|
637
|
+
poi.distance = calculateDistance(clickCoords, coordinates);
|
|
638
|
+
}
|
|
639
|
+
return poi;
|
|
640
|
+
}
|
|
641
|
+
function filterByDistance(features, clickCoords, radius) {
|
|
642
|
+
return features.filter((feature) => {
|
|
643
|
+
if (!feature.geometry || feature.geometry.type !== "Point") {
|
|
644
|
+
return false;
|
|
645
|
+
}
|
|
646
|
+
const featureCoords = feature.geometry.coordinates;
|
|
647
|
+
const distance = calculateDistance(clickCoords, featureCoords);
|
|
648
|
+
return distance <= radius;
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
function findNearestPOI(clickCoordinates, pois) {
|
|
652
|
+
if (!pois || pois.length === 0) {
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
let nearest = null;
|
|
656
|
+
let minDistance = Infinity;
|
|
657
|
+
for (const poi of pois) {
|
|
658
|
+
const distance = poi.distance ?? calculateDistance(clickCoordinates, poi.coordinates);
|
|
659
|
+
if (distance < minDistance) {
|
|
660
|
+
minDistance = distance;
|
|
661
|
+
nearest = { ...poi, distance };
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
return nearest;
|
|
665
|
+
}
|
|
666
|
+
async function searchPOIsForGeocoder(query, config) {
|
|
667
|
+
const results = [];
|
|
668
|
+
try {
|
|
669
|
+
if (config.customApiUrl) {
|
|
670
|
+
try {
|
|
671
|
+
const customFeatures = await queryCustomAPI(config.customApiUrl, query);
|
|
672
|
+
const customPOIs = customFeatures.map((feature) => geoJSONFeatureToPOI(feature, void 0, config.mapName, config.layerId)).filter((poi) => poi !== null).slice(0, 5);
|
|
673
|
+
results.push(...customPOIs);
|
|
674
|
+
} catch (error) {
|
|
675
|
+
console.warn("Custom API search failed:", error);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return results;
|
|
679
|
+
} catch (error) {
|
|
680
|
+
console.error("Search POIs error:", error);
|
|
681
|
+
return results;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
async function searchNearbyPOIsForSnap(lat, lng, config) {
|
|
685
|
+
const results = [];
|
|
686
|
+
try {
|
|
687
|
+
const nominatimPOIs = await queryNominatim(lat, lng, config.radius, config.nominatimUrl);
|
|
688
|
+
results.push(...nominatimPOIs);
|
|
689
|
+
if (config.customApiUrl) {
|
|
690
|
+
try {
|
|
691
|
+
const customFeatures = await queryCustomAPI(config.customApiUrl);
|
|
692
|
+
const nearbyFeatures = filterByDistance(customFeatures, [lng, lat], config.radius);
|
|
693
|
+
const customPOIs = nearbyFeatures.map(
|
|
694
|
+
(feature) => geoJSONFeatureToPOI(feature, [lng, lat], config.mapName, config.layerId)
|
|
695
|
+
).filter((poi) => poi !== null);
|
|
696
|
+
results.push(...customPOIs);
|
|
697
|
+
} catch (error) {
|
|
698
|
+
console.warn("Custom API query failed, continuing with Nominatim only:", error);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
return results;
|
|
702
|
+
} catch (error) {
|
|
703
|
+
console.error("Search nearby POIs error:", error);
|
|
704
|
+
return results;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
async function queryPOIsForViewport(bounds, center, maxDisplay, config) {
|
|
708
|
+
const results = [];
|
|
709
|
+
try {
|
|
710
|
+
if (config.customApiUrl) {
|
|
711
|
+
try {
|
|
712
|
+
const customFeatures = await queryCustomAPI(config.customApiUrl);
|
|
713
|
+
const viewportFeatures = customFeatures.filter((feature) => {
|
|
714
|
+
if (!feature.geometry || feature.geometry.type !== "Point") {
|
|
715
|
+
return false;
|
|
716
|
+
}
|
|
717
|
+
const [lng, lat] = feature.geometry.coordinates;
|
|
718
|
+
return lat >= bounds.south && lat <= bounds.north && lng >= bounds.west && lng <= bounds.east;
|
|
719
|
+
});
|
|
720
|
+
const customPOIs = viewportFeatures.map((feature) => geoJSONFeatureToPOI(feature, center, config.mapName, config.layerId)).filter((poi) => poi !== null);
|
|
721
|
+
results.push(...customPOIs);
|
|
722
|
+
} catch (error) {
|
|
723
|
+
console.warn("Custom API viewport query failed:", error);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
results.sort((a, b) => {
|
|
727
|
+
const distA = a.distance ?? calculateDistance(center, a.coordinates);
|
|
728
|
+
const distB = b.distance ?? calculateDistance(center, b.coordinates);
|
|
729
|
+
return distA - distB;
|
|
730
|
+
});
|
|
731
|
+
return results.slice(0, maxDisplay);
|
|
732
|
+
} catch (error) {
|
|
733
|
+
console.error("Query POIs for viewport error:", error);
|
|
734
|
+
return results;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
const USER_AGENT = "strapi-plugin-maplibre-field/1.0.0 (Strapi CMS)";
|
|
738
|
+
async function performSearch(query, config) {
|
|
739
|
+
const results = [];
|
|
740
|
+
if (config.poiSearchEnabled && config.poiSources) {
|
|
741
|
+
const enabledSources = config.poiSources.filter((source) => source.enabled !== false);
|
|
742
|
+
for (const source of enabledSources) {
|
|
743
|
+
try {
|
|
744
|
+
const poiResults = await searchPOIsForGeocoder(query, {
|
|
745
|
+
nominatimUrl: config.nominatimUrl,
|
|
746
|
+
customApiUrl: source.apiUrl,
|
|
747
|
+
mapName: source.name,
|
|
748
|
+
radius: 100,
|
|
749
|
+
categories: []
|
|
750
|
+
});
|
|
751
|
+
results.push(
|
|
752
|
+
...poiResults.map((poi, idx) => ({
|
|
753
|
+
id: `poi-${source.id}-${idx}`,
|
|
754
|
+
place_name: poi.name,
|
|
755
|
+
feature: {
|
|
756
|
+
type: "Feature",
|
|
757
|
+
geometry: {
|
|
758
|
+
type: "Point",
|
|
759
|
+
coordinates: poi.coordinates
|
|
760
|
+
},
|
|
761
|
+
properties: {
|
|
762
|
+
name: poi.name,
|
|
763
|
+
address: poi.address,
|
|
764
|
+
source: "custom",
|
|
765
|
+
sourceId: source.id,
|
|
766
|
+
sourceLayer: source.name,
|
|
767
|
+
category: poi.type,
|
|
768
|
+
// POI.type is the category
|
|
769
|
+
inputMethod: "search"
|
|
770
|
+
}
|
|
771
|
+
},
|
|
772
|
+
source: "custom"
|
|
773
|
+
}))
|
|
774
|
+
);
|
|
775
|
+
} catch (error) {
|
|
776
|
+
console.warn(`POI search failed for ${source.name}:`, error);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
try {
|
|
781
|
+
const response = await fetch(
|
|
782
|
+
`${config.nominatimUrl}/search?q=${encodeURIComponent(query)}&format=json&addressdetails=1&limit=5`,
|
|
783
|
+
{
|
|
784
|
+
headers: {
|
|
785
|
+
"User-Agent": USER_AGENT
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
);
|
|
789
|
+
if (response.ok) {
|
|
790
|
+
const data = await response.json();
|
|
791
|
+
results.push(
|
|
792
|
+
...data.map((result, idx) => ({
|
|
793
|
+
id: `nominatim-${idx}`,
|
|
794
|
+
place_name: result.display_name,
|
|
795
|
+
feature: {
|
|
796
|
+
type: "Feature",
|
|
797
|
+
geometry: {
|
|
798
|
+
type: "Point",
|
|
799
|
+
coordinates: [parseFloat(result.lon), parseFloat(result.lat)]
|
|
800
|
+
},
|
|
801
|
+
properties: {
|
|
802
|
+
name: result.display_name,
|
|
803
|
+
address: result.display_name,
|
|
804
|
+
source: "nominatim",
|
|
805
|
+
inputMethod: "search"
|
|
806
|
+
}
|
|
807
|
+
},
|
|
808
|
+
source: "nominatim"
|
|
809
|
+
}))
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
} catch (error) {
|
|
813
|
+
console.error("Nominatim search error:", error);
|
|
814
|
+
}
|
|
815
|
+
return results;
|
|
816
|
+
}
|
|
817
|
+
const SearchBox = ({
|
|
818
|
+
onSelectResult,
|
|
819
|
+
nominatimUrl,
|
|
820
|
+
poiSearchEnabled,
|
|
821
|
+
poiSources
|
|
822
|
+
}) => {
|
|
823
|
+
const { formatMessage } = useIntl();
|
|
824
|
+
const [query, setQuery] = React.useState("");
|
|
825
|
+
const [results, setResults] = React.useState([]);
|
|
826
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
827
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
828
|
+
const [hoveredId, setHoveredId] = React.useState(null);
|
|
829
|
+
const dropdownRef = React.useRef(null);
|
|
830
|
+
const containerRef = React.useRef(null);
|
|
831
|
+
React.useEffect(() => {
|
|
832
|
+
const handleClickOutside = (event) => {
|
|
833
|
+
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
834
|
+
setIsOpen(false);
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
if (isOpen) {
|
|
838
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
839
|
+
return () => {
|
|
840
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
}, [isOpen]);
|
|
844
|
+
const handleSearch = async () => {
|
|
845
|
+
if (!query.trim()) {
|
|
846
|
+
setResults([]);
|
|
847
|
+
setIsOpen(false);
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
setIsLoading(true);
|
|
851
|
+
try {
|
|
852
|
+
const searchResults = await performSearch(query, {
|
|
853
|
+
nominatimUrl,
|
|
854
|
+
poiSearchEnabled,
|
|
855
|
+
poiSources
|
|
856
|
+
});
|
|
857
|
+
setResults(searchResults);
|
|
858
|
+
setIsOpen(searchResults.length > 0);
|
|
859
|
+
} catch (error) {
|
|
860
|
+
console.error("Search error:", error);
|
|
861
|
+
setResults([]);
|
|
862
|
+
setIsOpen(false);
|
|
863
|
+
} finally {
|
|
864
|
+
setIsLoading(false);
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
const handleKeyDown = (e) => {
|
|
868
|
+
if (e.key === "Enter") {
|
|
869
|
+
e.preventDefault();
|
|
870
|
+
handleSearch();
|
|
871
|
+
} else if (e.key === "Escape") {
|
|
872
|
+
setIsOpen(false);
|
|
873
|
+
setQuery("");
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
const handleSelectResult = (result) => {
|
|
877
|
+
onSelectResult(result.feature);
|
|
878
|
+
setIsOpen(false);
|
|
879
|
+
setQuery("");
|
|
880
|
+
setResults([]);
|
|
881
|
+
};
|
|
882
|
+
const getResultColor = (result) => {
|
|
883
|
+
if (result.source === "nominatim") {
|
|
884
|
+
return "#6c757d";
|
|
885
|
+
}
|
|
886
|
+
const sourceId = result.feature.properties?.sourceId;
|
|
887
|
+
if (sourceId && poiSources) {
|
|
888
|
+
const source = poiSources.find((s) => s.id === sourceId);
|
|
889
|
+
if (source?.color) {
|
|
890
|
+
return source.color;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
return "#cc0000";
|
|
894
|
+
};
|
|
895
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { ref: containerRef, style: { position: "relative", width: "100%" }, children: [
|
|
896
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
897
|
+
designSystem.TextInput,
|
|
898
|
+
{
|
|
899
|
+
placeholder: formatMessage({ id: index.getTrad("search.placeholder") }),
|
|
900
|
+
value: query,
|
|
901
|
+
onChange: (e) => setQuery(e.target.value),
|
|
902
|
+
onKeyDown: handleKeyDown,
|
|
903
|
+
"aria-label": "Location search"
|
|
904
|
+
}
|
|
905
|
+
),
|
|
906
|
+
isOpen && results.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
907
|
+
designSystem.Box,
|
|
908
|
+
{
|
|
909
|
+
ref: dropdownRef,
|
|
910
|
+
background: "neutral0",
|
|
911
|
+
shadow: "filterShadow",
|
|
912
|
+
borderColor: "neutral150",
|
|
913
|
+
hasRadius: true,
|
|
914
|
+
padding: 2,
|
|
915
|
+
style: {
|
|
916
|
+
position: "absolute",
|
|
917
|
+
top: "calc(100% + 4px)",
|
|
918
|
+
left: 0,
|
|
919
|
+
right: 0,
|
|
920
|
+
zIndex: 1e3,
|
|
921
|
+
maxHeight: "300px",
|
|
922
|
+
overflowY: "auto"
|
|
923
|
+
},
|
|
924
|
+
children: results.map((result) => {
|
|
925
|
+
const dotColor = getResultColor(result);
|
|
926
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
927
|
+
designSystem.Box,
|
|
928
|
+
{
|
|
929
|
+
paddingTop: 2,
|
|
930
|
+
paddingBottom: 2,
|
|
931
|
+
paddingLeft: 3,
|
|
932
|
+
paddingRight: 3,
|
|
933
|
+
hasRadius: true,
|
|
934
|
+
background: hoveredId === result.id ? "primary100" : "neutral0",
|
|
935
|
+
onMouseEnter: () => setHoveredId(result.id),
|
|
936
|
+
onMouseLeave: () => setHoveredId(null),
|
|
937
|
+
onClick: () => handleSelectResult(result),
|
|
938
|
+
style: {
|
|
939
|
+
cursor: "pointer"
|
|
940
|
+
},
|
|
941
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
|
|
942
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
943
|
+
"div",
|
|
944
|
+
{
|
|
945
|
+
style: {
|
|
946
|
+
width: "10px",
|
|
947
|
+
height: "10px",
|
|
948
|
+
borderRadius: "50%",
|
|
949
|
+
backgroundColor: dotColor,
|
|
950
|
+
flexShrink: 0
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
),
|
|
954
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
955
|
+
designSystem.Typography,
|
|
956
|
+
{
|
|
957
|
+
variant: "omega",
|
|
958
|
+
textColor: "neutral800",
|
|
959
|
+
style: {
|
|
960
|
+
overflow: "hidden",
|
|
961
|
+
textOverflow: "ellipsis",
|
|
962
|
+
whiteSpace: "nowrap"
|
|
963
|
+
},
|
|
964
|
+
children: result.place_name
|
|
965
|
+
}
|
|
966
|
+
)
|
|
967
|
+
] })
|
|
968
|
+
},
|
|
969
|
+
result.id
|
|
970
|
+
);
|
|
971
|
+
})
|
|
972
|
+
}
|
|
973
|
+
),
|
|
974
|
+
isOpen && results.length === 0 && !isLoading && query.trim() && /* @__PURE__ */ jsxRuntime.jsx(
|
|
975
|
+
designSystem.Box,
|
|
976
|
+
{
|
|
977
|
+
background: "neutral0",
|
|
978
|
+
shadow: "filterShadow",
|
|
979
|
+
borderColor: "neutral150",
|
|
980
|
+
hasRadius: true,
|
|
981
|
+
padding: 4,
|
|
982
|
+
style: {
|
|
983
|
+
position: "absolute",
|
|
984
|
+
top: "calc(100% + 4px)",
|
|
985
|
+
left: 0,
|
|
986
|
+
right: 0,
|
|
987
|
+
zIndex: 1e3
|
|
988
|
+
},
|
|
989
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: [
|
|
990
|
+
'No results found for "',
|
|
991
|
+
query,
|
|
992
|
+
'"'
|
|
993
|
+
] })
|
|
994
|
+
}
|
|
995
|
+
)
|
|
996
|
+
] });
|
|
997
|
+
};
|
|
998
|
+
class BasemapControl {
|
|
999
|
+
constructor(_styles, _currentStyleUrl, _onStyleChange, _map, _container) {
|
|
1000
|
+
this._styles = _styles;
|
|
1001
|
+
this._currentStyleUrl = _currentStyleUrl;
|
|
1002
|
+
this._onStyleChange = _onStyleChange;
|
|
1003
|
+
this._map = _map;
|
|
1004
|
+
this._container = _container;
|
|
1005
|
+
}
|
|
1006
|
+
onAdd(map) {
|
|
1007
|
+
this._map = map;
|
|
1008
|
+
this._container = document.createElement("div");
|
|
1009
|
+
this._container.className = "maplibregl-ctrl maplibregl-ctrl-group";
|
|
1010
|
+
this._container.style.display = "flex";
|
|
1011
|
+
this._container.style.flexDirection = "row";
|
|
1012
|
+
this._styles.forEach((style, index2) => {
|
|
1013
|
+
const button = document.createElement("button");
|
|
1014
|
+
button.type = "button";
|
|
1015
|
+
button.title = style.name;
|
|
1016
|
+
button.setAttribute("aria-label", style.name);
|
|
1017
|
+
const span = document.createElement("span");
|
|
1018
|
+
span.textContent = style.name;
|
|
1019
|
+
span.style.padding = "0 8px";
|
|
1020
|
+
button.appendChild(span);
|
|
1021
|
+
button.className = "maplibregl-ctrl-icon";
|
|
1022
|
+
button.style.width = "auto";
|
|
1023
|
+
button.style.height = "29px";
|
|
1024
|
+
button.style.display = "flex";
|
|
1025
|
+
button.style.alignItems = "center";
|
|
1026
|
+
button.style.justifyContent = "center";
|
|
1027
|
+
if (style.url === this._currentStyleUrl) {
|
|
1028
|
+
button.style.backgroundColor = "rgba(0, 0, 0, 0.05)";
|
|
1029
|
+
button.style.fontWeight = "bold";
|
|
1030
|
+
}
|
|
1031
|
+
if (index2 < this._styles.length - 1) {
|
|
1032
|
+
button.style.borderRight = "1px solid rgba(0, 0, 0, 0.1)";
|
|
1033
|
+
}
|
|
1034
|
+
button.onclick = () => {
|
|
1035
|
+
const buttons = this._container?.querySelectorAll("button");
|
|
1036
|
+
buttons?.forEach((btn, btnIndex) => {
|
|
1037
|
+
if (btnIndex === index2) {
|
|
1038
|
+
btn.style.backgroundColor = "rgba(0, 0, 0, 0.05)";
|
|
1039
|
+
btn.style.fontWeight = "bold";
|
|
1040
|
+
} else {
|
|
1041
|
+
btn.style.backgroundColor = "";
|
|
1042
|
+
btn.style.fontWeight = "";
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
1045
|
+
this._onStyleChange(style.url);
|
|
1046
|
+
};
|
|
1047
|
+
this._container.appendChild(button);
|
|
1048
|
+
});
|
|
1049
|
+
return this._container;
|
|
1050
|
+
}
|
|
1051
|
+
onRemove() {
|
|
1052
|
+
this._container?.parentNode?.removeChild(this._container);
|
|
1053
|
+
this._map = void 0;
|
|
1054
|
+
}
|
|
1055
|
+
updateCurrentStyle(styleUrl) {
|
|
1056
|
+
this._currentStyleUrl = styleUrl;
|
|
1057
|
+
const buttons = this._container?.querySelectorAll("button");
|
|
1058
|
+
buttons?.forEach((button, index2) => {
|
|
1059
|
+
const btn = button;
|
|
1060
|
+
if (this._styles[index2].url === styleUrl) {
|
|
1061
|
+
btn.style.backgroundColor = "rgba(0, 0, 0, 0.05)";
|
|
1062
|
+
btn.style.fontWeight = "bold";
|
|
1063
|
+
} else {
|
|
1064
|
+
btn.style.backgroundColor = "";
|
|
1065
|
+
btn.style.fontWeight = "";
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
function BasemapControlComponent({
|
|
1071
|
+
mapStyles,
|
|
1072
|
+
currentStyleUrl,
|
|
1073
|
+
onStyleChange
|
|
1074
|
+
}) {
|
|
1075
|
+
const controlRef = Map.useControl(
|
|
1076
|
+
() => new BasemapControl(mapStyles, currentStyleUrl, onStyleChange),
|
|
1077
|
+
{
|
|
1078
|
+
position: "bottom-left"
|
|
1079
|
+
}
|
|
1080
|
+
);
|
|
1081
|
+
React.useEffect(() => {
|
|
1082
|
+
if (controlRef && "updateCurrentStyle" in controlRef) {
|
|
1083
|
+
controlRef.updateCurrentStyle(currentStyleUrl);
|
|
1084
|
+
}
|
|
1085
|
+
}, [currentStyleUrl, controlRef]);
|
|
1086
|
+
return null;
|
|
1087
|
+
}
|
|
1088
|
+
class LayerControlImpl {
|
|
1089
|
+
constructor(_layers, _onToggle, _map, _container) {
|
|
1090
|
+
this._layers = _layers;
|
|
1091
|
+
this._onToggle = _onToggle;
|
|
1092
|
+
this._map = _map;
|
|
1093
|
+
this._container = _container;
|
|
1094
|
+
}
|
|
1095
|
+
onAdd(map) {
|
|
1096
|
+
this._map = map;
|
|
1097
|
+
this._container = document.createElement("div");
|
|
1098
|
+
this._container.className = "maplibregl-ctrl maplibregl-ctrl-group";
|
|
1099
|
+
this._container.style.padding = "0";
|
|
1100
|
+
this._render();
|
|
1101
|
+
return this._container;
|
|
1102
|
+
}
|
|
1103
|
+
onRemove() {
|
|
1104
|
+
if (this._container && this._container.parentNode) {
|
|
1105
|
+
this._container.parentNode.removeChild(this._container);
|
|
1106
|
+
}
|
|
1107
|
+
this._map = void 0;
|
|
1108
|
+
}
|
|
1109
|
+
_render() {
|
|
1110
|
+
if (!this._container) return;
|
|
1111
|
+
this._container.innerHTML = "";
|
|
1112
|
+
const button = document.createElement("button");
|
|
1113
|
+
button.type = "button";
|
|
1114
|
+
button.className = "maplibregl-ctrl-icon";
|
|
1115
|
+
button.title = "Toggle Layers";
|
|
1116
|
+
button.setAttribute("aria-label", "Toggle Layers");
|
|
1117
|
+
button.innerHTML = `
|
|
1118
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1119
|
+
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
|
|
1120
|
+
<path d="M2 17l10 5 10-5"/>
|
|
1121
|
+
<path d="M2 12l10 5 10-5"/>
|
|
1122
|
+
</svg>
|
|
1123
|
+
`;
|
|
1124
|
+
button.style.width = "29px";
|
|
1125
|
+
button.style.height = "29px";
|
|
1126
|
+
button.style.cursor = "pointer";
|
|
1127
|
+
button.style.border = "none";
|
|
1128
|
+
button.style.padding = "0";
|
|
1129
|
+
button.style.display = "flex";
|
|
1130
|
+
button.style.alignItems = "center";
|
|
1131
|
+
button.style.justifyContent = "center";
|
|
1132
|
+
const panel = document.createElement("div");
|
|
1133
|
+
panel.className = "maplibregl-ctrl-layers-panel";
|
|
1134
|
+
panel.style.display = "none";
|
|
1135
|
+
panel.style.position = "absolute";
|
|
1136
|
+
panel.style.top = "0";
|
|
1137
|
+
panel.style.right = "40px";
|
|
1138
|
+
panel.style.background = "white";
|
|
1139
|
+
panel.style.borderRadius = "4px";
|
|
1140
|
+
panel.style.boxShadow = "0 0 0 2px rgba(0, 0, 0, 0.1)";
|
|
1141
|
+
panel.style.padding = "8px";
|
|
1142
|
+
panel.style.minWidth = "180px";
|
|
1143
|
+
panel.style.maxHeight = "300px";
|
|
1144
|
+
panel.style.overflowY = "auto";
|
|
1145
|
+
const title = document.createElement("div");
|
|
1146
|
+
title.textContent = "POI Layers";
|
|
1147
|
+
title.style.fontSize = "12px";
|
|
1148
|
+
title.style.fontWeight = "bold";
|
|
1149
|
+
title.style.marginBottom = "8px";
|
|
1150
|
+
title.style.color = "#333";
|
|
1151
|
+
title.style.fontFamily = "system-ui, -apple-system, sans-serif";
|
|
1152
|
+
panel.appendChild(title);
|
|
1153
|
+
this._layers.forEach((layer) => {
|
|
1154
|
+
const layerItem = document.createElement("div");
|
|
1155
|
+
layerItem.style.display = "flex";
|
|
1156
|
+
layerItem.style.alignItems = "center";
|
|
1157
|
+
layerItem.style.padding = "4px 0";
|
|
1158
|
+
layerItem.style.cursor = "pointer";
|
|
1159
|
+
layerItem.style.fontSize = "12px";
|
|
1160
|
+
layerItem.style.color = "#333";
|
|
1161
|
+
layerItem.style.fontFamily = "system-ui, -apple-system, sans-serif";
|
|
1162
|
+
const circle = document.createElement("div");
|
|
1163
|
+
circle.style.width = "12px";
|
|
1164
|
+
circle.style.height = "12px";
|
|
1165
|
+
circle.style.borderRadius = "50%";
|
|
1166
|
+
circle.style.marginRight = "8px";
|
|
1167
|
+
circle.style.cursor = "pointer";
|
|
1168
|
+
circle.style.flexShrink = "0";
|
|
1169
|
+
circle.style.transition = "all 0.2s ease";
|
|
1170
|
+
if (layer.enabled && layer.color) {
|
|
1171
|
+
circle.style.backgroundColor = layer.color;
|
|
1172
|
+
circle.style.border = "none";
|
|
1173
|
+
} else {
|
|
1174
|
+
circle.style.backgroundColor = "transparent";
|
|
1175
|
+
circle.style.border = "2px solid #999";
|
|
1176
|
+
}
|
|
1177
|
+
layerItem.addEventListener("click", (e) => {
|
|
1178
|
+
e.stopPropagation();
|
|
1179
|
+
this._onToggle(layer.id, !layer.enabled);
|
|
1180
|
+
});
|
|
1181
|
+
const labelText = document.createElement("span");
|
|
1182
|
+
labelText.textContent = layer.name;
|
|
1183
|
+
labelText.style.userSelect = "none";
|
|
1184
|
+
layerItem.appendChild(circle);
|
|
1185
|
+
layerItem.appendChild(labelText);
|
|
1186
|
+
panel.appendChild(layerItem);
|
|
1187
|
+
});
|
|
1188
|
+
let isPanelOpen = false;
|
|
1189
|
+
button.addEventListener("click", (e) => {
|
|
1190
|
+
e.stopPropagation();
|
|
1191
|
+
isPanelOpen = !isPanelOpen;
|
|
1192
|
+
panel.style.display = isPanelOpen ? "block" : "none";
|
|
1193
|
+
});
|
|
1194
|
+
document.addEventListener("click", (e) => {
|
|
1195
|
+
if (isPanelOpen && this._container && !this._container.contains(e.target)) {
|
|
1196
|
+
isPanelOpen = false;
|
|
1197
|
+
panel.style.display = "none";
|
|
1198
|
+
}
|
|
1199
|
+
});
|
|
1200
|
+
this._container.appendChild(button);
|
|
1201
|
+
this._container.appendChild(panel);
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Update layers (e.g., when toggled externally)
|
|
1205
|
+
*/
|
|
1206
|
+
updateLayers(layers) {
|
|
1207
|
+
this._layers = layers;
|
|
1208
|
+
this._render();
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
const LayerControl = ({ mapRef, layers, onLayerToggle }) => {
|
|
1212
|
+
const controlRef = React.useRef(null);
|
|
1213
|
+
React.useEffect(() => {
|
|
1214
|
+
if (!mapRef.current || layers.length === 0) return;
|
|
1215
|
+
const map = mapRef.current.getMap();
|
|
1216
|
+
const control = new LayerControlImpl(layers, onLayerToggle);
|
|
1217
|
+
controlRef.current = control;
|
|
1218
|
+
map.addControl(control, "top-right");
|
|
1219
|
+
return () => {
|
|
1220
|
+
if (controlRef.current) {
|
|
1221
|
+
map.removeControl(controlRef.current);
|
|
1222
|
+
controlRef.current = null;
|
|
1223
|
+
}
|
|
1224
|
+
};
|
|
1225
|
+
}, [mapRef, onLayerToggle]);
|
|
1226
|
+
React.useEffect(() => {
|
|
1227
|
+
if (controlRef.current) {
|
|
1228
|
+
controlRef.current.updateLayers(layers);
|
|
1229
|
+
}
|
|
1230
|
+
}, [layers]);
|
|
1231
|
+
return null;
|
|
1232
|
+
};
|
|
1233
|
+
const DEFAULT_CONFIG = {
|
|
1234
|
+
mapStyles: [
|
|
1235
|
+
{
|
|
1236
|
+
id: "default",
|
|
1237
|
+
name: "Default",
|
|
1238
|
+
url: "https://tiles.openfreemap.org/styles/liberty",
|
|
1239
|
+
isDefault: true
|
|
1240
|
+
}
|
|
1241
|
+
],
|
|
1242
|
+
defaultZoom: 4.5,
|
|
1243
|
+
defaultCenter: [0, 0],
|
|
1244
|
+
// Null Island - fallback if not configured
|
|
1245
|
+
geocodingProvider: "nominatim",
|
|
1246
|
+
nominatimUrl: "https://nominatim.openstreetmap.org"
|
|
1247
|
+
};
|
|
1248
|
+
const usePluginConfig = () => {
|
|
1249
|
+
const [config, setConfig] = React.useState(DEFAULT_CONFIG);
|
|
1250
|
+
const { get } = admin.useFetchClient();
|
|
1251
|
+
React.useEffect(() => {
|
|
1252
|
+
const fetchConfig = async () => {
|
|
1253
|
+
try {
|
|
1254
|
+
const response = await get("/maplibre-field/config");
|
|
1255
|
+
if (response.data) {
|
|
1256
|
+
setConfig({ ...DEFAULT_CONFIG, ...response.data });
|
|
1257
|
+
}
|
|
1258
|
+
} catch {
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
fetchConfig();
|
|
1262
|
+
}, [get]);
|
|
1263
|
+
return config;
|
|
1264
|
+
};
|
|
1265
|
+
const protocol = new pmtiles.Protocol();
|
|
1266
|
+
maplibregl__default.default.addProtocol("pmtiles", protocol.tile);
|
|
1267
|
+
const MapField = ({ intlLabel, name, onChange, value }) => {
|
|
1268
|
+
const { formatMessage } = useIntl();
|
|
1269
|
+
const { toggleNotification } = admin.useNotification();
|
|
1270
|
+
const config = usePluginConfig();
|
|
1271
|
+
const mapRef = React.useRef(null);
|
|
1272
|
+
const label = intlLabel || { id: "maplibre-field.label", defaultMessage: "Map" };
|
|
1273
|
+
let result = null;
|
|
1274
|
+
if (value) {
|
|
1275
|
+
try {
|
|
1276
|
+
const parsed = typeof value === "string" ? JSON.parse(value) : value;
|
|
1277
|
+
if (parsed && typeof parsed === "object" && parsed.geometry?.coordinates) {
|
|
1278
|
+
result = parsed;
|
|
1279
|
+
}
|
|
1280
|
+
} catch (error) {
|
|
1281
|
+
console.error("MapField: Invalid JSON value", error);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
const isDefaultViewState = result == null;
|
|
1285
|
+
let initialCoordinates = config.defaultCenter || [0, 0];
|
|
1286
|
+
if (result?.geometry?.coordinates && Array.isArray(result.geometry.coordinates)) {
|
|
1287
|
+
const [lng, lat] = result.geometry.coordinates;
|
|
1288
|
+
if (typeof lng === "number" && typeof lat === "number" && !isNaN(lng) && !isNaN(lat)) {
|
|
1289
|
+
initialCoordinates = [lng, lat];
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
const isNullIsland = initialCoordinates[0] === 0 && initialCoordinates[1] === 0;
|
|
1293
|
+
const initialAddress = result?.properties?.name || result?.properties?.address || (isNullIsland ? "Null Island" : "");
|
|
1294
|
+
const [longitude, setLongitude] = React.useState(initialCoordinates[0]);
|
|
1295
|
+
const [latitude, setLatitude] = React.useState(initialCoordinates[1]);
|
|
1296
|
+
const [address, setAddress] = React.useState(initialAddress);
|
|
1297
|
+
const [viewState, setViewState] = React.useState({
|
|
1298
|
+
longitude: initialCoordinates[0],
|
|
1299
|
+
latitude: initialCoordinates[1],
|
|
1300
|
+
zoom: isDefaultViewState ? config.defaultZoom || 4.5 : 15
|
|
1301
|
+
// Use zoom 15 when coordinates are saved
|
|
1302
|
+
});
|
|
1303
|
+
const [currentStyleUrl, setCurrentStyleUrl] = React.useState(() => {
|
|
1304
|
+
if (config.mapStyles && config.mapStyles.length > 0) {
|
|
1305
|
+
const defaultStyle = config.mapStyles.find((s) => s.isDefault);
|
|
1306
|
+
return defaultStyle?.url || config.mapStyles[0].url;
|
|
1307
|
+
}
|
|
1308
|
+
return "";
|
|
1309
|
+
});
|
|
1310
|
+
const [displayedPOIs, setDisplayedPOIs] = React.useState([]);
|
|
1311
|
+
const [selectedPOI, setSelectedPOI] = React.useState(null);
|
|
1312
|
+
const [isUpdatingPOIs, setIsUpdatingPOIs] = React.useState(false);
|
|
1313
|
+
const updatePOITimerRef = React.useRef(null);
|
|
1314
|
+
const poiLayersRef = React.useRef([]);
|
|
1315
|
+
const [poiLayers, setPoiLayers] = React.useState(() => {
|
|
1316
|
+
if (!config.poiDisplayEnabled) return [];
|
|
1317
|
+
if (config.poiSources && config.poiSources.length > 0) {
|
|
1318
|
+
return config.poiSources.map((source) => ({
|
|
1319
|
+
id: source.id,
|
|
1320
|
+
name: source.name,
|
|
1321
|
+
enabled: source.enabled !== false,
|
|
1322
|
+
// Default to enabled if not specified
|
|
1323
|
+
color: source.color
|
|
1324
|
+
// Pass the color from config
|
|
1325
|
+
}));
|
|
1326
|
+
}
|
|
1327
|
+
return [];
|
|
1328
|
+
});
|
|
1329
|
+
React.useEffect(() => {
|
|
1330
|
+
poiLayersRef.current = poiLayers;
|
|
1331
|
+
}, [poiLayers]);
|
|
1332
|
+
React.useEffect(() => {
|
|
1333
|
+
if (config.defaultZoom && isDefaultViewState) {
|
|
1334
|
+
setViewState((prev) => ({
|
|
1335
|
+
...prev,
|
|
1336
|
+
zoom: config.defaultZoom ?? prev.zoom
|
|
1337
|
+
}));
|
|
1338
|
+
}
|
|
1339
|
+
}, [config.defaultZoom, isDefaultViewState]);
|
|
1340
|
+
React.useEffect(() => {
|
|
1341
|
+
if (config.defaultCenter && isDefaultViewState) {
|
|
1342
|
+
const [lng, lat] = config.defaultCenter;
|
|
1343
|
+
const isNullIsland2 = lng === 0 && lat === 0;
|
|
1344
|
+
setLongitude(lng);
|
|
1345
|
+
setLatitude(lat);
|
|
1346
|
+
setAddress(isNullIsland2 ? "Null Island" : "");
|
|
1347
|
+
setViewState((prev) => ({
|
|
1348
|
+
...prev,
|
|
1349
|
+
longitude: lng,
|
|
1350
|
+
latitude: lat
|
|
1351
|
+
}));
|
|
1352
|
+
}
|
|
1353
|
+
}, [config.defaultCenter, isDefaultViewState]);
|
|
1354
|
+
React.useEffect(() => {
|
|
1355
|
+
if (config.mapStyles && config.mapStyles.length > 0) {
|
|
1356
|
+
const defaultStyle = config.mapStyles.find((s) => s.isDefault);
|
|
1357
|
+
const newStyleUrl = defaultStyle?.url || config.mapStyles[0].url;
|
|
1358
|
+
if (newStyleUrl && newStyleUrl !== currentStyleUrl) {
|
|
1359
|
+
setCurrentStyleUrl(newStyleUrl);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
}, [config.mapStyles]);
|
|
1363
|
+
React.useEffect(() => {
|
|
1364
|
+
if (!config.poiDisplayEnabled) {
|
|
1365
|
+
setPoiLayers([]);
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
if (config.poiSources && config.poiSources.length > 0) {
|
|
1369
|
+
setPoiLayers(
|
|
1370
|
+
config.poiSources.map((source) => ({
|
|
1371
|
+
id: source.id,
|
|
1372
|
+
name: source.name,
|
|
1373
|
+
enabled: source.enabled !== false,
|
|
1374
|
+
color: source.color
|
|
1375
|
+
// Pass the color from config
|
|
1376
|
+
}))
|
|
1377
|
+
);
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
setPoiLayers([]);
|
|
1381
|
+
}, [config.poiDisplayEnabled, config.poiSources]);
|
|
1382
|
+
const handleStyleChange = (newStyleUrl) => {
|
|
1383
|
+
if (!mapRef.current) return;
|
|
1384
|
+
const map = mapRef.current.getMap();
|
|
1385
|
+
const currentCenter = map.getCenter();
|
|
1386
|
+
const currentZoom = map.getZoom();
|
|
1387
|
+
map.setStyle(newStyleUrl);
|
|
1388
|
+
map.once("styledata", () => {
|
|
1389
|
+
map.setCenter(currentCenter);
|
|
1390
|
+
map.setZoom(currentZoom);
|
|
1391
|
+
});
|
|
1392
|
+
setCurrentStyleUrl(newStyleUrl);
|
|
1393
|
+
};
|
|
1394
|
+
const handleLayerToggle = (layerId, enabled) => {
|
|
1395
|
+
setPoiLayers(
|
|
1396
|
+
(prevLayers) => prevLayers.map((layer) => layer.id === layerId ? { ...layer, enabled } : layer)
|
|
1397
|
+
);
|
|
1398
|
+
};
|
|
1399
|
+
const updatePOIMarkers = async () => {
|
|
1400
|
+
if (updatePOITimerRef.current) {
|
|
1401
|
+
clearTimeout(updatePOITimerRef.current);
|
|
1402
|
+
}
|
|
1403
|
+
updatePOITimerRef.current = setTimeout(async () => {
|
|
1404
|
+
const currentPoiLayers = poiLayersRef.current;
|
|
1405
|
+
const hasEnabledLayers = currentPoiLayers.some((layer) => layer.enabled);
|
|
1406
|
+
if (!mapRef.current || !config.poiDisplayEnabled) {
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
if (!hasEnabledLayers) {
|
|
1410
|
+
setDisplayedPOIs([]);
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
if (isUpdatingPOIs) {
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
const map = mapRef.current.getMap();
|
|
1417
|
+
const zoom = map.getZoom();
|
|
1418
|
+
if (zoom < (config.poiMinZoom || 10)) {
|
|
1419
|
+
setDisplayedPOIs([]);
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
const bounds = map.getBounds();
|
|
1423
|
+
const center = map.getCenter();
|
|
1424
|
+
try {
|
|
1425
|
+
setIsUpdatingPOIs(true);
|
|
1426
|
+
const enabledLayers = currentPoiLayers.filter((layer) => layer.enabled);
|
|
1427
|
+
const allPOIs = [];
|
|
1428
|
+
for (const layer of enabledLayers) {
|
|
1429
|
+
let apiUrl = null;
|
|
1430
|
+
let mapName = layer.name;
|
|
1431
|
+
if (config.poiSources) {
|
|
1432
|
+
const source = config.poiSources.find((s) => s.id === layer.id);
|
|
1433
|
+
if (source) {
|
|
1434
|
+
apiUrl = source.apiUrl;
|
|
1435
|
+
mapName = source.name;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
if (apiUrl) {
|
|
1439
|
+
const pois = await queryPOIsForViewport(
|
|
1440
|
+
{
|
|
1441
|
+
north: bounds.getNorth(),
|
|
1442
|
+
south: bounds.getSouth(),
|
|
1443
|
+
east: bounds.getEast(),
|
|
1444
|
+
west: bounds.getWest()
|
|
1445
|
+
},
|
|
1446
|
+
[center.lng, center.lat],
|
|
1447
|
+
config.poiMaxDisplay || 100,
|
|
1448
|
+
{
|
|
1449
|
+
nominatimUrl: config.nominatimUrl || "https://nominatim.openstreetmap.org",
|
|
1450
|
+
customApiUrl: apiUrl,
|
|
1451
|
+
mapName,
|
|
1452
|
+
layerId: layer.id,
|
|
1453
|
+
// Pass the layer ID
|
|
1454
|
+
radius: 100,
|
|
1455
|
+
categories: []
|
|
1456
|
+
}
|
|
1457
|
+
);
|
|
1458
|
+
allPOIs.push(...pois);
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
requestAnimationFrame(() => {
|
|
1462
|
+
setDisplayedPOIs(allPOIs);
|
|
1463
|
+
setIsUpdatingPOIs(false);
|
|
1464
|
+
});
|
|
1465
|
+
} catch (error) {
|
|
1466
|
+
console.error("Failed to load POIs:", error);
|
|
1467
|
+
setIsUpdatingPOIs(false);
|
|
1468
|
+
}
|
|
1469
|
+
}, 300);
|
|
1470
|
+
};
|
|
1471
|
+
const handleMainMarkerClick = () => {
|
|
1472
|
+
toggleNotification({
|
|
1473
|
+
type: "info",
|
|
1474
|
+
message: `Marker: [${longitude.toFixed(4)}, ${latitude.toFixed(4)}]`
|
|
1475
|
+
});
|
|
1476
|
+
};
|
|
1477
|
+
const handlePOIClick = async (poi) => {
|
|
1478
|
+
setSelectedPOI(poi);
|
|
1479
|
+
const address2 = poi.address || "";
|
|
1480
|
+
updateValues(
|
|
1481
|
+
createLocationFeature(poi.coordinates, {
|
|
1482
|
+
name: poi.name,
|
|
1483
|
+
address: address2,
|
|
1484
|
+
source: poi.source === "custom" ? poi.layerId : "nominatim",
|
|
1485
|
+
sourceId: poi.id,
|
|
1486
|
+
sourceLayer: poi.mapName,
|
|
1487
|
+
category: poi.type,
|
|
1488
|
+
inputMethod: "poi_click",
|
|
1489
|
+
metadata: poi.metadata
|
|
1490
|
+
})
|
|
1491
|
+
);
|
|
1492
|
+
toggleNotification({
|
|
1493
|
+
type: "success",
|
|
1494
|
+
message: poi.mapName ? `${poi.mapName} ➙ ${poi.name}` : `Selected ${poi.name}`
|
|
1495
|
+
});
|
|
1496
|
+
};
|
|
1497
|
+
const handleMapClick = (evt) => {
|
|
1498
|
+
if (!mapRef.current) return;
|
|
1499
|
+
const map = mapRef.current.getMap();
|
|
1500
|
+
const poiLayer = map.getLayer("poi-circles");
|
|
1501
|
+
if (!poiLayer) {
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
const features = map.queryRenderedFeatures(evt.point, {
|
|
1505
|
+
layers: ["poi-circles"]
|
|
1506
|
+
});
|
|
1507
|
+
if (features && features.length > 0) {
|
|
1508
|
+
const feature = features[0];
|
|
1509
|
+
const featureName = feature.properties?.name;
|
|
1510
|
+
let clickedPOI = displayedPOIs.find((p) => p.name === featureName);
|
|
1511
|
+
if (!clickedPOI) {
|
|
1512
|
+
clickedPOI = displayedPOIs.find((p) => p.id === feature.id);
|
|
1513
|
+
}
|
|
1514
|
+
if (!clickedPOI && feature.id !== void 0) {
|
|
1515
|
+
clickedPOI = displayedPOIs.find((p) => p.id === String(feature.id));
|
|
1516
|
+
}
|
|
1517
|
+
if (clickedPOI) {
|
|
1518
|
+
handlePOIClick(clickedPOI);
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
};
|
|
1523
|
+
const handleMapDoubleClick = async (evt) => {
|
|
1524
|
+
evt.preventDefault();
|
|
1525
|
+
const clickCoords = [evt.lngLat.lng, evt.lngLat.lat];
|
|
1526
|
+
const snapRadius = typeof config.poiSnapRadius === "number" ? config.poiSnapRadius : 5;
|
|
1527
|
+
try {
|
|
1528
|
+
const enabledLayers = poiLayers.filter((layer) => layer.enabled);
|
|
1529
|
+
const allNearbyPOIs = [];
|
|
1530
|
+
for (const layer of enabledLayers) {
|
|
1531
|
+
let apiUrl = null;
|
|
1532
|
+
let mapName = layer.name;
|
|
1533
|
+
if (config.poiSources) {
|
|
1534
|
+
const source = config.poiSources.find((s) => s.id === layer.id);
|
|
1535
|
+
if (source) {
|
|
1536
|
+
apiUrl = source.apiUrl;
|
|
1537
|
+
mapName = source.name;
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
if (apiUrl) {
|
|
1541
|
+
const pois = await searchNearbyPOIsForSnap(
|
|
1542
|
+
clickCoords[1],
|
|
1543
|
+
// lat
|
|
1544
|
+
clickCoords[0],
|
|
1545
|
+
// lng
|
|
1546
|
+
{
|
|
1547
|
+
nominatimUrl: config.nominatimUrl || "https://nominatim.openstreetmap.org",
|
|
1548
|
+
customApiUrl: apiUrl,
|
|
1549
|
+
mapName,
|
|
1550
|
+
layerId: layer.id,
|
|
1551
|
+
// Pass the layer ID
|
|
1552
|
+
radius: snapRadius,
|
|
1553
|
+
categories: []
|
|
1554
|
+
}
|
|
1555
|
+
);
|
|
1556
|
+
allNearbyPOIs.push(...pois);
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
const nearestPOI = findNearestPOI(clickCoords, allNearbyPOIs);
|
|
1560
|
+
if (nearestPOI && nearestPOI.distance !== void 0 && nearestPOI.distance <= snapRadius) {
|
|
1561
|
+
await handlePOIClick(nearestPOI);
|
|
1562
|
+
toggleNotification({
|
|
1563
|
+
type: "success",
|
|
1564
|
+
message: `${nearestPOI.name} (${Math.round(nearestPOI.distance)}m)`
|
|
1565
|
+
});
|
|
1566
|
+
} else {
|
|
1567
|
+
updateValues(
|
|
1568
|
+
createLocationFeature(clickCoords, {
|
|
1569
|
+
inputMethod: "map_click"
|
|
1570
|
+
})
|
|
1571
|
+
);
|
|
1572
|
+
toggleNotification({
|
|
1573
|
+
type: "info",
|
|
1574
|
+
message: formatMessage({
|
|
1575
|
+
id: index.getTrad("coordinates-saved"),
|
|
1576
|
+
defaultMessage: "Coordinates set"
|
|
1577
|
+
})
|
|
1578
|
+
});
|
|
1579
|
+
}
|
|
1580
|
+
} catch (error) {
|
|
1581
|
+
console.error("Failed to search nearby POIs:", error);
|
|
1582
|
+
updateValues(
|
|
1583
|
+
createLocationFeature(clickCoords, {
|
|
1584
|
+
inputMethod: "map_click"
|
|
1585
|
+
})
|
|
1586
|
+
);
|
|
1587
|
+
toggleNotification({
|
|
1588
|
+
type: "info",
|
|
1589
|
+
message: formatMessage({
|
|
1590
|
+
id: index.getTrad("coordinates-saved"),
|
|
1591
|
+
defaultMessage: "Coordinates set"
|
|
1592
|
+
})
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
};
|
|
1596
|
+
const updateValues = (feature) => {
|
|
1597
|
+
if (!feature) return;
|
|
1598
|
+
const value2 = JSON.stringify(feature);
|
|
1599
|
+
setAddress(feature.properties.name || feature.properties.address || "");
|
|
1600
|
+
setLongitude(feature.geometry.coordinates[0]);
|
|
1601
|
+
setLatitude(feature.geometry.coordinates[1]);
|
|
1602
|
+
onChange({ target: { name, value: value2, type: "json" } });
|
|
1603
|
+
};
|
|
1604
|
+
const handleSearchResult = (feature) => {
|
|
1605
|
+
if (feature.geometry?.coordinates) {
|
|
1606
|
+
const [lng, lat] = feature.geometry.coordinates;
|
|
1607
|
+
mapRef.current?.flyTo({
|
|
1608
|
+
center: [lng, lat],
|
|
1609
|
+
zoom: 16,
|
|
1610
|
+
essential: true
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
updateValues(feature);
|
|
1614
|
+
toggleNotification({
|
|
1615
|
+
type: "success",
|
|
1616
|
+
message: `Location set to: ${feature.properties.name || feature.properties.address}`
|
|
1617
|
+
});
|
|
1618
|
+
};
|
|
1619
|
+
React.useEffect(() => {
|
|
1620
|
+
if (!isDefaultViewState && mapRef.current) {
|
|
1621
|
+
const map = mapRef.current.getMap();
|
|
1622
|
+
map?.flyTo({ center: [longitude, latitude], zoom: 15 });
|
|
1623
|
+
}
|
|
1624
|
+
}, [longitude, latitude, isDefaultViewState]);
|
|
1625
|
+
React.useEffect(() => {
|
|
1626
|
+
const protocol2 = new pmtiles.Protocol();
|
|
1627
|
+
maplibregl__default.default.addProtocol("pmtiles", protocol2.tile);
|
|
1628
|
+
return () => {
|
|
1629
|
+
maplibregl__default.default.removeProtocol("pmtiles");
|
|
1630
|
+
};
|
|
1631
|
+
}, []);
|
|
1632
|
+
React.useEffect(() => {
|
|
1633
|
+
if (!mapRef.current || !config.poiDisplayEnabled) return;
|
|
1634
|
+
const map = mapRef.current.getMap();
|
|
1635
|
+
const handleMapUpdate = () => {
|
|
1636
|
+
updatePOIMarkers();
|
|
1637
|
+
};
|
|
1638
|
+
map.once("load", handleMapUpdate);
|
|
1639
|
+
map.on("moveend", handleMapUpdate);
|
|
1640
|
+
map.on("zoomend", handleMapUpdate);
|
|
1641
|
+
return () => {
|
|
1642
|
+
map.off("moveend", handleMapUpdate);
|
|
1643
|
+
map.off("zoomend", handleMapUpdate);
|
|
1644
|
+
if (updatePOITimerRef.current) {
|
|
1645
|
+
clearTimeout(updatePOITimerRef.current);
|
|
1646
|
+
}
|
|
1647
|
+
};
|
|
1648
|
+
}, [config.poiDisplayEnabled, config.poiMinZoom, config.poiMaxDisplay, config.poiSources]);
|
|
1649
|
+
React.useEffect(() => {
|
|
1650
|
+
if (!mapRef.current || !config.poiDisplayEnabled) return;
|
|
1651
|
+
updatePOIMarkers();
|
|
1652
|
+
}, [JSON.stringify(poiLayers.map((l) => ({ id: l.id, enabled: l.enabled })))]);
|
|
1653
|
+
React.useEffect(() => {
|
|
1654
|
+
if (!mapRef.current || !config.poiDisplayEnabled) return;
|
|
1655
|
+
const map = mapRef.current.getMap();
|
|
1656
|
+
const handleMouseEnter = () => {
|
|
1657
|
+
map.getCanvas().style.cursor = "pointer";
|
|
1658
|
+
};
|
|
1659
|
+
const handleMouseLeave = () => {
|
|
1660
|
+
map.getCanvas().style.cursor = "";
|
|
1661
|
+
};
|
|
1662
|
+
map.on("load", () => {
|
|
1663
|
+
map.on("mouseenter", "poi-circles", handleMouseEnter);
|
|
1664
|
+
map.on("mouseleave", "poi-circles", handleMouseLeave);
|
|
1665
|
+
});
|
|
1666
|
+
return () => {
|
|
1667
|
+
map.off("mouseenter", "poi-circles", handleMouseEnter);
|
|
1668
|
+
map.off("mouseleave", "poi-circles", handleMouseLeave);
|
|
1669
|
+
};
|
|
1670
|
+
}, [config.poiDisplayEnabled]);
|
|
1671
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
|
|
1672
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", variant: "pi", fontWeight: "bold", children: formatMessage(label) }),
|
|
1673
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1674
|
+
SearchBox,
|
|
1675
|
+
{
|
|
1676
|
+
onSelectResult: handleSearchResult,
|
|
1677
|
+
nominatimUrl: config.nominatimUrl || "https://nominatim.openstreetmap.org",
|
|
1678
|
+
poiSearchEnabled: config.poiSearchEnabled,
|
|
1679
|
+
poiSources: config.poiSources
|
|
1680
|
+
}
|
|
1681
|
+
),
|
|
1682
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1683
|
+
designSystem.Flex,
|
|
1684
|
+
{
|
|
1685
|
+
direction: "column",
|
|
1686
|
+
alignItems: "stretch",
|
|
1687
|
+
style: {
|
|
1688
|
+
height: "500px",
|
|
1689
|
+
width: "100%",
|
|
1690
|
+
borderRadius: "4px",
|
|
1691
|
+
overflow: "hidden"
|
|
1692
|
+
},
|
|
1693
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1694
|
+
Map__default.default,
|
|
1695
|
+
{
|
|
1696
|
+
ref: mapRef,
|
|
1697
|
+
...viewState,
|
|
1698
|
+
onMove: (evt) => setViewState(evt.viewState),
|
|
1699
|
+
onClick: handleMapClick,
|
|
1700
|
+
onDblClick: handleMapDoubleClick,
|
|
1701
|
+
mapStyle: currentStyleUrl,
|
|
1702
|
+
children: [
|
|
1703
|
+
/* @__PURE__ */ jsxRuntime.jsx(Map.FullscreenControl, { pseudo: config.useFullscreenPseudo ?? true }),
|
|
1704
|
+
/* @__PURE__ */ jsxRuntime.jsx(Map.NavigationControl, {}),
|
|
1705
|
+
/* @__PURE__ */ jsxRuntime.jsx(Map.GeolocateControl, {}),
|
|
1706
|
+
config.mapStyles && config.mapStyles.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1707
|
+
BasemapControlComponent,
|
|
1708
|
+
{
|
|
1709
|
+
mapStyles: config.mapStyles,
|
|
1710
|
+
currentStyleUrl,
|
|
1711
|
+
onStyleChange: handleStyleChange
|
|
1712
|
+
}
|
|
1713
|
+
),
|
|
1714
|
+
poiLayers.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(LayerControl, { mapRef, layers: poiLayers, onLayerToggle: handleLayerToggle }),
|
|
1715
|
+
config.poiDisplayEnabled && displayedPOIs.length > 0 && (() => {
|
|
1716
|
+
const layerColorMap = {};
|
|
1717
|
+
poiLayers.forEach((layer) => {
|
|
1718
|
+
if (layer.color) {
|
|
1719
|
+
layerColorMap[layer.id] = layer.color;
|
|
1720
|
+
}
|
|
1721
|
+
});
|
|
1722
|
+
const colorMatchExpression = ["match", ["get", "layerId"]];
|
|
1723
|
+
Object.entries(layerColorMap).forEach(([layerId, color]) => {
|
|
1724
|
+
colorMatchExpression.push(layerId, color);
|
|
1725
|
+
});
|
|
1726
|
+
colorMatchExpression.push("#999999");
|
|
1727
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1728
|
+
Map.Source,
|
|
1729
|
+
{
|
|
1730
|
+
id: "poi-markers",
|
|
1731
|
+
type: "geojson",
|
|
1732
|
+
data: {
|
|
1733
|
+
type: "FeatureCollection",
|
|
1734
|
+
features: displayedPOIs.slice(0, 100).map((poi) => ({
|
|
1735
|
+
type: "Feature",
|
|
1736
|
+
id: poi.id,
|
|
1737
|
+
geometry: {
|
|
1738
|
+
type: "Point",
|
|
1739
|
+
coordinates: poi.coordinates
|
|
1740
|
+
},
|
|
1741
|
+
properties: {
|
|
1742
|
+
name: poi.name || "Unknown",
|
|
1743
|
+
type: poi.type || "poi",
|
|
1744
|
+
source: poi.source,
|
|
1745
|
+
layerId: poi.layerId || "",
|
|
1746
|
+
// Include layerId for color mapping
|
|
1747
|
+
isSelected: selectedPOI?.id === poi.id
|
|
1748
|
+
}
|
|
1749
|
+
}))
|
|
1750
|
+
},
|
|
1751
|
+
children: [
|
|
1752
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1753
|
+
Map.Layer,
|
|
1754
|
+
{
|
|
1755
|
+
id: "poi-circles",
|
|
1756
|
+
type: "circle",
|
|
1757
|
+
paint: {
|
|
1758
|
+
"circle-radius": [
|
|
1759
|
+
"case",
|
|
1760
|
+
["get", "isSelected"],
|
|
1761
|
+
12,
|
|
1762
|
+
// Larger radius for selected
|
|
1763
|
+
10
|
|
1764
|
+
// Regular radius
|
|
1765
|
+
],
|
|
1766
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1767
|
+
"circle-color": colorMatchExpression,
|
|
1768
|
+
// Use dynamic color mapping based on layerId per POI
|
|
1769
|
+
"circle-stroke-width": 2,
|
|
1770
|
+
"circle-stroke-color": "#ffffff",
|
|
1771
|
+
"circle-opacity": [
|
|
1772
|
+
"case",
|
|
1773
|
+
["get", "isSelected"],
|
|
1774
|
+
0.8,
|
|
1775
|
+
// Selected POI opacity
|
|
1776
|
+
1
|
|
1777
|
+
// Regular POI opacity
|
|
1778
|
+
]
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
),
|
|
1782
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1783
|
+
Map.Layer,
|
|
1784
|
+
{
|
|
1785
|
+
id: "poi-labels",
|
|
1786
|
+
type: "symbol",
|
|
1787
|
+
minzoom: 12,
|
|
1788
|
+
layout: {
|
|
1789
|
+
"text-field": ["get", "name"],
|
|
1790
|
+
"text-size": 12,
|
|
1791
|
+
"text-offset": [0, 1.5],
|
|
1792
|
+
"text-anchor": "top",
|
|
1793
|
+
"text-optional": true,
|
|
1794
|
+
"symbol-placement": "point",
|
|
1795
|
+
"text-allow-overlap": false,
|
|
1796
|
+
"text-ignore-placement": false
|
|
1797
|
+
},
|
|
1798
|
+
paint: {
|
|
1799
|
+
"text-color": "#333333",
|
|
1800
|
+
"text-halo-color": "#ffffff",
|
|
1801
|
+
"text-halo-width": 2
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
)
|
|
1805
|
+
]
|
|
1806
|
+
},
|
|
1807
|
+
`poi-source-${displayedPOIs.length}-${selectedPOI?.id || "none"}`
|
|
1808
|
+
);
|
|
1809
|
+
})(),
|
|
1810
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1811
|
+
Map.Marker,
|
|
1812
|
+
{
|
|
1813
|
+
longitude,
|
|
1814
|
+
latitude,
|
|
1815
|
+
color: "#4945ff",
|
|
1816
|
+
onClick: handleMainMarkerClick
|
|
1817
|
+
}
|
|
1818
|
+
)
|
|
1819
|
+
]
|
|
1820
|
+
}
|
|
1821
|
+
)
|
|
1822
|
+
}
|
|
1823
|
+
),
|
|
1824
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { children: [
|
|
1825
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { padding: 1, col: 6, xs: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
|
|
1826
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
|
|
1827
|
+
id: result?.properties?.sourceId ? index.getTrad("fields.poi-name") : index.getTrad("fields.address"),
|
|
1828
|
+
defaultMessage: result?.properties?.sourceId ? "POI Name" : "Address"
|
|
1829
|
+
}) }),
|
|
1830
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Input, { name: "place_name", value: address, disabled: true })
|
|
1831
|
+
] }) }),
|
|
1832
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { padding: 1, col: 3, xs: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
|
|
1833
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
|
|
1834
|
+
id: index.getTrad("fields.longitude"),
|
|
1835
|
+
defaultMessage: "Longitude"
|
|
1836
|
+
}) }),
|
|
1837
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Input, { name: "longitude", value: longitude, disabled: true })
|
|
1838
|
+
] }) }),
|
|
1839
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { padding: 1, col: 3, xs: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
|
|
1840
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
|
|
1841
|
+
id: index.getTrad("fields.latitude"),
|
|
1842
|
+
defaultMessage: "Latitude"
|
|
1843
|
+
}) }),
|
|
1844
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Input, { name: "latitude", value: latitude, disabled: true })
|
|
1845
|
+
] }) }),
|
|
1846
|
+
result?.properties?.sourceId && result?.properties?.address && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { padding: 1, col: 12, xs: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
|
|
1847
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
|
|
1848
|
+
id: index.getTrad("fields.poi-address"),
|
|
1849
|
+
defaultMessage: "Full Address"
|
|
1850
|
+
}) }),
|
|
1851
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Input, { name: "poi_address", value: result.properties.address, disabled: true })
|
|
1852
|
+
] }) })
|
|
1853
|
+
] })
|
|
1854
|
+
] });
|
|
1855
|
+
};
|
|
1856
|
+
exports.default = MapField;
|