zenit-sdk 0.0.8 → 0.0.9
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/README.md +32 -0
- package/dist/{chunk-52CLFD4L.mjs → chunk-PCTRVN4O.mjs} +1075 -1004
- package/dist/chunk-PCTRVN4O.mjs.map +1 -0
- package/dist/{index-kGwfqTc_.d.mts → index-DvcYGhqj.d.mts} +70 -4
- package/dist/{index-kGwfqTc_.d.ts → index-DvcYGhqj.d.ts} +70 -4
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1218 -1026
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +119 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +1077 -1006
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1 -1
- package/package.json +10 -7
- package/dist/chunk-52CLFD4L.mjs.map +0 -1
package/dist/react/index.js
CHANGED
|
@@ -58,9 +58,9 @@ __export(react_exports, {
|
|
|
58
58
|
module.exports = __toCommonJS(react_exports);
|
|
59
59
|
|
|
60
60
|
// src/react/ZenitMap.tsx
|
|
61
|
-
var
|
|
62
|
-
var
|
|
63
|
-
var
|
|
61
|
+
var import_react4 = __toESM(require("react"));
|
|
62
|
+
var import_react_leaflet4 = require("react-leaflet");
|
|
63
|
+
var import_leaflet4 = __toESM(require("leaflet"));
|
|
64
64
|
|
|
65
65
|
// src/maps/helpers.ts
|
|
66
66
|
function toNumber(value) {
|
|
@@ -253,9 +253,9 @@ function getAccentByLayerId(layerId, mapLayers) {
|
|
|
253
253
|
|
|
254
254
|
// src/react/zoomOpacity.ts
|
|
255
255
|
var DEFAULT_OPTIONS = {
|
|
256
|
-
minZoom:
|
|
257
|
-
maxZoom:
|
|
258
|
-
minFactor: 0.
|
|
256
|
+
minZoom: 11,
|
|
257
|
+
maxZoom: 15,
|
|
258
|
+
minFactor: 0.3,
|
|
259
259
|
maxFactor: 1,
|
|
260
260
|
minOpacity: 0.1,
|
|
261
261
|
maxOpacity: 0.92
|
|
@@ -292,358 +292,215 @@ function getEffectiveLayerOpacity(baseOpacity, zoom, layerType, geometryType, op
|
|
|
292
292
|
return clampNumber(effective, settings.minOpacity, settings.maxOpacity);
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
// src/react/
|
|
295
|
+
// src/react/map/layer-geojson.tsx
|
|
296
|
+
var import_react_leaflet = require("react-leaflet");
|
|
297
|
+
var import_leaflet = __toESM(require("leaflet"));
|
|
296
298
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
297
|
-
var
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
if (!geojson) return null;
|
|
302
|
-
if (!Array.isArray(geojson.features) || geojson.features.length === 0) return null;
|
|
303
|
-
const coords = [];
|
|
304
|
-
const collect = (candidate) => {
|
|
305
|
-
if (!Array.isArray(candidate)) return;
|
|
306
|
-
if (candidate.length === 2 && typeof candidate[0] === "number" && typeof candidate[1] === "number") {
|
|
307
|
-
coords.push([candidate[0], candidate[1]]);
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
candidate.forEach((entry) => collect(entry));
|
|
311
|
-
};
|
|
312
|
-
geojson.features.forEach((feature) => {
|
|
313
|
-
collect(feature.geometry?.coordinates);
|
|
314
|
-
});
|
|
315
|
-
if (coords.length === 0) return null;
|
|
316
|
-
const [firstLon, firstLat] = coords[0];
|
|
317
|
-
const bbox = { minLon: firstLon, minLat: firstLat, maxLon: firstLon, maxLat: firstLat };
|
|
318
|
-
coords.forEach(([lon, lat]) => {
|
|
319
|
-
bbox.minLon = Math.min(bbox.minLon, lon);
|
|
320
|
-
bbox.minLat = Math.min(bbox.minLat, lat);
|
|
321
|
-
bbox.maxLon = Math.max(bbox.maxLon, lon);
|
|
322
|
-
bbox.maxLat = Math.max(bbox.maxLat, lat);
|
|
323
|
-
});
|
|
324
|
-
return bbox;
|
|
325
|
-
}
|
|
326
|
-
function mergeBBoxes(bboxes) {
|
|
327
|
-
const valid = bboxes.filter((bbox) => !!bbox);
|
|
328
|
-
if (valid.length === 0) return null;
|
|
329
|
-
const first = valid[0];
|
|
330
|
-
return valid.slice(1).reduce(
|
|
331
|
-
(acc, bbox) => ({
|
|
332
|
-
minLon: Math.min(acc.minLon, bbox.minLon),
|
|
333
|
-
minLat: Math.min(acc.minLat, bbox.minLat),
|
|
334
|
-
maxLon: Math.max(acc.maxLon, bbox.maxLon),
|
|
335
|
-
maxLat: Math.max(acc.maxLat, bbox.maxLat)
|
|
336
|
-
}),
|
|
337
|
-
{ ...first }
|
|
338
|
-
);
|
|
339
|
-
}
|
|
340
|
-
function isRecord(value) {
|
|
341
|
-
return typeof value === "object" && value !== null;
|
|
299
|
+
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
300
|
+
function getGeometryType(feature) {
|
|
301
|
+
const t = feature?.geometry?.type;
|
|
302
|
+
return typeof t === "string" ? t : null;
|
|
342
303
|
}
|
|
343
|
-
function
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
if (!Array.isArray(features)) return false;
|
|
347
|
-
const type = value.type;
|
|
348
|
-
return type === void 0 || type === "FeatureCollection";
|
|
304
|
+
function isPointGeometry(feature) {
|
|
305
|
+
const geometryType = getGeometryType(feature);
|
|
306
|
+
return geometryType !== null && POINT_GEOMETRY_TYPES.has(geometryType);
|
|
349
307
|
}
|
|
350
|
-
function
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
return isGeoJsonFeatureCollection(data) ? data : null;
|
|
354
|
-
}
|
|
355
|
-
return isGeoJsonFeatureCollection(value) ? value : null;
|
|
308
|
+
function isNonPointGeometry(feature) {
|
|
309
|
+
const geometryType = getGeometryType(feature);
|
|
310
|
+
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
356
311
|
}
|
|
357
|
-
function
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
312
|
+
function buildFeatureCollection(features) {
|
|
313
|
+
return {
|
|
314
|
+
type: "FeatureCollection",
|
|
315
|
+
features
|
|
316
|
+
};
|
|
361
317
|
}
|
|
362
|
-
|
|
363
|
-
|
|
318
|
+
var LayerGeoJson = ({
|
|
319
|
+
layerId,
|
|
320
|
+
data,
|
|
321
|
+
baseOpacity,
|
|
322
|
+
isMobile,
|
|
323
|
+
panesReady,
|
|
324
|
+
mapInstance,
|
|
325
|
+
fillPaneName,
|
|
326
|
+
pointsPaneName,
|
|
327
|
+
layerType,
|
|
328
|
+
styleFn,
|
|
329
|
+
onEachFeature,
|
|
330
|
+
onPolygonLabel
|
|
331
|
+
}) => {
|
|
332
|
+
const features = data.features ?? [];
|
|
333
|
+
const fillFeatures = features.filter(isNonPointGeometry);
|
|
334
|
+
const pointFeatures = features.filter(isPointGeometry);
|
|
335
|
+
const fillData = fillFeatures.length > 0 ? buildFeatureCollection(fillFeatures) : null;
|
|
336
|
+
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
337
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
338
|
+
fillData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
339
|
+
import_react_leaflet.GeoJSON,
|
|
340
|
+
{
|
|
341
|
+
data: fillData,
|
|
342
|
+
pane: panesReady && mapInstance?.getPane(fillPaneName) ? fillPaneName : void 0,
|
|
343
|
+
style: (feature) => styleFn(feature, layerType, baseOpacity),
|
|
344
|
+
onEachFeature: (feature, layer) => {
|
|
345
|
+
onEachFeature(feature, layer);
|
|
346
|
+
onPolygonLabel?.(feature, layer);
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
`fill-${layerId}`
|
|
350
|
+
),
|
|
351
|
+
pointsData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
352
|
+
import_react_leaflet.GeoJSON,
|
|
353
|
+
{
|
|
354
|
+
data: pointsData,
|
|
355
|
+
pane: panesReady && mapInstance?.getPane(pointsPaneName) ? pointsPaneName : void 0,
|
|
356
|
+
pointToLayer: (feature, latlng) => import_leaflet.default.circleMarker(latlng, {
|
|
357
|
+
radius: isMobile ? 8 : 6,
|
|
358
|
+
...styleFn(feature, layerType, baseOpacity)
|
|
359
|
+
}),
|
|
360
|
+
onEachFeature
|
|
361
|
+
},
|
|
362
|
+
`points-${layerId}`
|
|
363
|
+
)
|
|
364
|
+
] });
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
// src/react/map/location-control.tsx
|
|
368
|
+
var import_react2 = require("react");
|
|
369
|
+
var import_react_dom = require("react-dom");
|
|
370
|
+
var import_react_leaflet2 = require("react-leaflet");
|
|
371
|
+
var import_leaflet3 = __toESM(require("leaflet"));
|
|
372
|
+
|
|
373
|
+
// src/react/hooks/use-geolocation.ts
|
|
374
|
+
var import_react = require("react");
|
|
375
|
+
function useGeolocation(options) {
|
|
376
|
+
const [isTracking, setIsTracking] = (0, import_react.useState)(false);
|
|
377
|
+
const [location, setLocation] = (0, import_react.useState)(null);
|
|
378
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
379
|
+
const watchIdRef = (0, import_react.useRef)(null);
|
|
380
|
+
const stopTracking = (0, import_react.useCallback)(() => {
|
|
381
|
+
if (watchIdRef.current !== null && typeof navigator !== "undefined" && navigator.geolocation) {
|
|
382
|
+
navigator.geolocation.clearWatch(watchIdRef.current);
|
|
383
|
+
}
|
|
384
|
+
watchIdRef.current = null;
|
|
385
|
+
setIsTracking(false);
|
|
386
|
+
}, []);
|
|
387
|
+
const startTracking = (0, import_react.useCallback)(() => {
|
|
388
|
+
if (typeof navigator === "undefined" || !navigator.geolocation) {
|
|
389
|
+
setError({ code: 0, message: "La geolocalizaci\xF3n no est\xE1 disponible en este navegador." });
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
setError(null);
|
|
393
|
+
watchIdRef.current = navigator.geolocation.watchPosition(
|
|
394
|
+
(position) => {
|
|
395
|
+
setLocation({
|
|
396
|
+
lat: position.coords.latitude,
|
|
397
|
+
lon: position.coords.longitude,
|
|
398
|
+
accuracy: position.coords.accuracy
|
|
399
|
+
});
|
|
400
|
+
setIsTracking(true);
|
|
401
|
+
},
|
|
402
|
+
(err) => {
|
|
403
|
+
setError({ code: err.code, message: err.message });
|
|
404
|
+
stopTracking();
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
enableHighAccuracy: options?.enableHighAccuracy ?? true,
|
|
408
|
+
timeout: options?.timeout ?? 12e3,
|
|
409
|
+
maximumAge: options?.maximumAge ?? 0
|
|
410
|
+
}
|
|
411
|
+
);
|
|
412
|
+
}, [options?.enableHighAccuracy, options?.maximumAge, options?.timeout, stopTracking]);
|
|
413
|
+
const toggleTracking = (0, import_react.useCallback)(() => {
|
|
414
|
+
if (isTracking) {
|
|
415
|
+
stopTracking();
|
|
416
|
+
} else {
|
|
417
|
+
startTracking();
|
|
418
|
+
}
|
|
419
|
+
}, [isTracking, startTracking, stopTracking]);
|
|
420
|
+
const clearError = (0, import_react.useCallback)(() => setError(null), []);
|
|
421
|
+
(0, import_react.useEffect)(() => {
|
|
422
|
+
return () => {
|
|
423
|
+
stopTracking();
|
|
424
|
+
};
|
|
425
|
+
}, [stopTracking]);
|
|
426
|
+
return {
|
|
427
|
+
isTracking,
|
|
428
|
+
location,
|
|
429
|
+
error,
|
|
430
|
+
startTracking,
|
|
431
|
+
stopTracking,
|
|
432
|
+
toggleTracking,
|
|
433
|
+
clearError
|
|
434
|
+
};
|
|
364
435
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
var
|
|
436
|
+
|
|
437
|
+
// src/react/map/map-utils.ts
|
|
438
|
+
var import_leaflet2 = __toESM(require("leaflet"));
|
|
368
439
|
var POPUP_STYLE_ID = "zenit-leaflet-popup-styles";
|
|
369
|
-
var
|
|
370
|
-
var
|
|
440
|
+
var POPUP_EXCLUDED_KEYS = /* @__PURE__ */ new Set(["geom", "geometry", "_private"]);
|
|
441
|
+
var POPUP_HEADER_KEYS = ["nombre", "name", "title", "titulo"];
|
|
442
|
+
var DESKTOP_POPUP_DIMENSIONS = { maxWidth: 360, minWidth: 280, maxHeight: 520 };
|
|
443
|
+
var MOBILE_POPUP_DIMENSIONS = { maxWidth: 300, minWidth: 240, maxHeight: 420 };
|
|
371
444
|
var ZENIT_LEAFLET_POPUP_STYLES = `
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
/* Main popup wrapper */
|
|
375
|
-
.zenit-leaflet-popup .leaflet-popup-content-wrapper {
|
|
445
|
+
.custom-leaflet-popup .leaflet-popup-content-wrapper {
|
|
376
446
|
border-radius: 12px;
|
|
377
|
-
box-shadow:
|
|
378
|
-
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
379
|
-
0 2px 4px -2px rgba(0, 0, 0, 0.1),
|
|
380
|
-
0 0 0 1px rgba(0, 0, 0, 0.05);
|
|
381
447
|
padding: 0;
|
|
382
448
|
background: #ffffff;
|
|
383
|
-
|
|
449
|
+
box-shadow: 0 12px 24px rgba(15, 23, 42, 0.18);
|
|
450
|
+
border: 1px solid rgba(15, 23, 42, 0.08);
|
|
384
451
|
}
|
|
385
452
|
|
|
386
|
-
|
|
387
|
-
.zenit-leaflet-popup .leaflet-popup-content {
|
|
453
|
+
.custom-leaflet-popup .leaflet-popup-content {
|
|
388
454
|
margin: 0;
|
|
389
|
-
padding:
|
|
455
|
+
padding: 12px 14px;
|
|
390
456
|
font-size: 13px;
|
|
391
|
-
line-height: 1.5;
|
|
392
|
-
color: #374151;
|
|
393
|
-
min-width: 100%;
|
|
394
|
-
max-height: min(70vh, 480px);
|
|
395
|
-
overflow-y: auto;
|
|
396
|
-
overflow-x: hidden;
|
|
397
|
-
scrollbar-width: thin;
|
|
398
|
-
scrollbar-color: rgba(156, 163, 175, 0.5) transparent;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
/* Popup tip/arrow shadow */
|
|
402
|
-
.zenit-leaflet-popup .leaflet-popup-tip-container {
|
|
403
|
-
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
.zenit-leaflet-popup .leaflet-popup-tip {
|
|
407
|
-
background: #ffffff;
|
|
408
|
-
box-shadow: none;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
/* Close button styling */
|
|
412
|
-
.zenit-leaflet-popup .leaflet-popup-close-button {
|
|
413
|
-
color: #9ca3af;
|
|
414
|
-
font-size: 18px;
|
|
415
|
-
font-weight: 400;
|
|
416
|
-
width: 28px;
|
|
417
|
-
height: 28px;
|
|
418
|
-
padding: 0;
|
|
419
|
-
margin: 8px 8px 0 0;
|
|
420
|
-
display: flex;
|
|
421
|
-
align-items: center;
|
|
422
|
-
justify-content: center;
|
|
423
|
-
border-radius: 6px;
|
|
424
|
-
transition: all 0.15s ease;
|
|
425
|
-
z-index: 10;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
.zenit-leaflet-popup .leaflet-popup-close-button:hover {
|
|
429
|
-
color: #374151;
|
|
430
|
-
background-color: #f3f4f6;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
.zenit-leaflet-popup .leaflet-popup-close-button:active {
|
|
434
|
-
background-color: #e5e7eb;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
/* Main card container */
|
|
438
|
-
.zenit-popup-card {
|
|
439
|
-
display: flex;
|
|
440
|
-
flex-direction: column;
|
|
441
|
-
gap: 0;
|
|
442
|
-
padding: 16px;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
.zenit-popup-header {
|
|
446
|
-
padding-bottom: 12px;
|
|
447
|
-
border-bottom: 1px solid #e5e7eb;
|
|
448
|
-
margin-bottom: 4px;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
.zenit-popup-title {
|
|
452
|
-
font-size: 14px;
|
|
453
|
-
font-weight: 700;
|
|
454
|
-
color: #111827;
|
|
455
|
-
letter-spacing: 0.01em;
|
|
456
|
-
line-height: 1.4;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
/* Individual row styling with subtle separator */
|
|
460
|
-
.zenit-popup-row {
|
|
461
|
-
display: flex;
|
|
462
|
-
flex-direction: column;
|
|
463
|
-
gap: 2px;
|
|
464
|
-
padding: 10px 0;
|
|
465
|
-
border-bottom: 1px solid #f3f4f6;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
.zenit-popup-row:first-child {
|
|
469
|
-
padding-top: 0;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
.zenit-popup-row:last-child {
|
|
473
|
-
border-bottom: none;
|
|
474
|
-
padding-bottom: 0;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
/* Label styling - small, gray, uppercase */
|
|
478
|
-
.zenit-popup-label {
|
|
479
|
-
font-size: 10px;
|
|
480
|
-
font-weight: 500;
|
|
481
|
-
color: #9ca3af;
|
|
482
|
-
text-transform: uppercase;
|
|
483
|
-
letter-spacing: 0.05em;
|
|
484
457
|
line-height: 1.4;
|
|
458
|
+
color: #0f172a;
|
|
459
|
+
max-height: min(70vh, 520px);
|
|
460
|
+
overflow: auto;
|
|
461
|
+
scrollbar-width: thin;
|
|
462
|
+
scrollbar-color: rgba(148, 163, 184, 0.6) transparent;
|
|
485
463
|
}
|
|
486
464
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
font-size:
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
word-break: break-word;
|
|
494
|
-
line-height: 1.5;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
.zenit-popup-link {
|
|
498
|
-
color: #2563eb;
|
|
499
|
-
text-decoration: underline;
|
|
500
|
-
font-weight: 500;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
.zenit-popup-link:hover {
|
|
504
|
-
color: #1d4ed8;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
/* Special styling for description field */
|
|
508
|
-
.zenit-popup-row.zenit-popup-description {
|
|
509
|
-
background-color: #f9fafb;
|
|
510
|
-
margin: 0 -16px;
|
|
511
|
-
padding: 12px 16px;
|
|
512
|
-
border-bottom: 1px solid #e5e7eb;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
.zenit-popup-row.zenit-popup-description:first-child {
|
|
516
|
-
margin-top: 0;
|
|
517
|
-
border-radius: 0;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value {
|
|
521
|
-
font-size: 13px;
|
|
522
|
-
line-height: 1.6;
|
|
523
|
-
color: #374151;
|
|
524
|
-
max-height: 150px;
|
|
525
|
-
overflow-y: auto;
|
|
526
|
-
padding-right: 4px;
|
|
465
|
+
.custom-leaflet-popup .leaflet-popup-close-button {
|
|
466
|
+
color: #64748b;
|
|
467
|
+
font-size: 16px;
|
|
468
|
+
padding: 6px 8px;
|
|
469
|
+
border-radius: 8px;
|
|
470
|
+
transition: background-color 0.15s ease, color 0.15s ease;
|
|
527
471
|
}
|
|
528
472
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
533
|
-
font-size: 11px;
|
|
534
|
-
white-space: pre-wrap;
|
|
535
|
-
word-break: break-word;
|
|
536
|
-
color: #4b5563;
|
|
537
|
-
background-color: #f9fafb;
|
|
538
|
-
padding: 8px;
|
|
539
|
-
border-radius: 6px;
|
|
540
|
-
border: 1px solid #e5e7eb;
|
|
473
|
+
.custom-leaflet-popup .leaflet-popup-close-button:hover {
|
|
474
|
+
color: #0f172a;
|
|
475
|
+
background: rgba(148, 163, 184, 0.2);
|
|
541
476
|
}
|
|
542
477
|
|
|
543
|
-
|
|
544
|
-
.zenit-popup-empty {
|
|
545
|
-
font-size: 13px;
|
|
546
|
-
color: #9ca3af;
|
|
547
|
-
font-style: italic;
|
|
548
|
-
text-align: center;
|
|
549
|
-
padding: 20px 0;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
/* Webkit scrollbar styling */
|
|
553
|
-
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar {
|
|
478
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar {
|
|
554
479
|
width: 6px;
|
|
555
480
|
}
|
|
556
481
|
|
|
557
|
-
.
|
|
558
|
-
background:
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb {
|
|
562
|
-
background-color: rgba(156, 163, 175, 0.4);
|
|
563
|
-
border-radius: 3px;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb:hover {
|
|
567
|
-
background-color: rgba(107, 114, 128, 0.6);
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
/* Scrollbar for description field */
|
|
571
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar {
|
|
572
|
-
width: 4px;
|
|
482
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb {
|
|
483
|
+
background: rgba(148, 163, 184, 0.5);
|
|
484
|
+
border-radius: 999px;
|
|
573
485
|
}
|
|
574
486
|
|
|
575
|
-
.
|
|
487
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-track {
|
|
576
488
|
background: transparent;
|
|
577
489
|
}
|
|
578
490
|
|
|
579
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar-thumb {
|
|
580
|
-
background-color: rgba(156, 163, 175, 0.4);
|
|
581
|
-
border-radius: 2px;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
/* ===== Responsive: Mobile (<640px) ===== */
|
|
585
491
|
@media (max-width: 640px) {
|
|
586
|
-
.
|
|
587
|
-
border-radius: 10px;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
.zenit-leaflet-popup .leaflet-popup-close-button {
|
|
591
|
-
width: 26px;
|
|
592
|
-
height: 26px;
|
|
593
|
-
font-size: 16px;
|
|
594
|
-
margin: 6px 6px 0 0;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
.zenit-popup-card {
|
|
598
|
-
padding: 12px;
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
.zenit-leaflet-popup .leaflet-popup-content {
|
|
602
|
-
max-height: min(65vh, 380px);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
.zenit-popup-header {
|
|
606
|
-
padding-bottom: 10px;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
.zenit-popup-title {
|
|
610
|
-
font-size: 13px;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
.zenit-popup-row {
|
|
614
|
-
padding: 8px 0;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
.zenit-popup-label {
|
|
618
|
-
font-size: 9px;
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
.zenit-popup-value {
|
|
492
|
+
.custom-leaflet-popup .leaflet-popup-content {
|
|
622
493
|
font-size: 12px;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
.zenit-popup-row.zenit-popup-description {
|
|
626
|
-
margin: 0 -12px;
|
|
627
494
|
padding: 10px 12px;
|
|
495
|
+
max-height: min(65vh, 420px);
|
|
628
496
|
}
|
|
629
497
|
|
|
630
|
-
.
|
|
631
|
-
font-size:
|
|
632
|
-
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
.zenit-popup-pre {
|
|
636
|
-
font-size: 10px;
|
|
637
|
-
padding: 6px;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
.zenit-popup-empty {
|
|
641
|
-
font-size: 12px;
|
|
642
|
-
padding: 16px 0;
|
|
498
|
+
.custom-leaflet-popup .leaflet-popup-close-button {
|
|
499
|
+
font-size: 14px;
|
|
500
|
+
padding: 4px 6px;
|
|
643
501
|
}
|
|
644
502
|
}
|
|
645
503
|
|
|
646
|
-
/* ===== Map tooltip styling ===== */
|
|
647
504
|
.zenit-map-tooltip {
|
|
648
505
|
background-color: rgba(31, 41, 55, 0.95);
|
|
649
506
|
border: none;
|
|
@@ -660,16 +517,21 @@ var ZENIT_LEAFLET_POPUP_STYLES = `
|
|
|
660
517
|
}
|
|
661
518
|
|
|
662
519
|
.polygon-label-tooltip {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
display: none !important;
|
|
520
|
+
background: rgba(15, 23, 42, 0.92);
|
|
521
|
+
border: none;
|
|
522
|
+
border-radius: 6px;
|
|
523
|
+
color: #f8fafc;
|
|
524
|
+
font-weight: 600;
|
|
525
|
+
font-size: 12px;
|
|
526
|
+
padding: 4px 8px;
|
|
671
527
|
}
|
|
672
528
|
`;
|
|
529
|
+
function clampNumber2(value, min, max) {
|
|
530
|
+
return Math.min(max, Math.max(min, value));
|
|
531
|
+
}
|
|
532
|
+
function clampOpacity4(value) {
|
|
533
|
+
return clampNumber2(value, 0, 1);
|
|
534
|
+
}
|
|
673
535
|
function ensurePopupStyles() {
|
|
674
536
|
if (typeof document === "undefined") return;
|
|
675
537
|
if (document.getElementById(POPUP_STYLE_ID)) return;
|
|
@@ -679,72 +541,52 @@ function ensurePopupStyles() {
|
|
|
679
541
|
document.head.appendChild(styleTag);
|
|
680
542
|
}
|
|
681
543
|
function getPopupDimensions() {
|
|
682
|
-
if (typeof window === "undefined"
|
|
544
|
+
if (typeof window === "undefined") {
|
|
683
545
|
return DESKTOP_POPUP_DIMENSIONS;
|
|
684
546
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
const trimmed = value.trim();
|
|
691
|
-
return trimmed ? trimmed : null;
|
|
692
|
-
}
|
|
693
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
694
|
-
return String(value);
|
|
695
|
-
}
|
|
696
|
-
return null;
|
|
547
|
+
const isSmallWidth = window.innerWidth < 640;
|
|
548
|
+
const isShortHeight = window.innerHeight < 768;
|
|
549
|
+
const base = isSmallWidth ? MOBILE_POPUP_DIMENSIONS : DESKTOP_POPUP_DIMENSIONS;
|
|
550
|
+
const maxHeight = isShortHeight ? Math.min(base.maxHeight, 360) : base.maxHeight;
|
|
551
|
+
return { ...base, maxHeight };
|
|
697
552
|
}
|
|
698
|
-
function
|
|
699
|
-
|
|
700
|
-
const matches = Object.entries(properties).find(
|
|
701
|
-
([key]) => DESCRIPTION_KEYS.has(key.toLowerCase())
|
|
702
|
-
);
|
|
703
|
-
if (!matches) return null;
|
|
704
|
-
return normalizeDescriptionValue(matches[1]);
|
|
553
|
+
function escapeHtml(value) {
|
|
554
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
705
555
|
}
|
|
706
|
-
function
|
|
707
|
-
|
|
708
|
-
const json = JSON.stringify(value, null, 2);
|
|
709
|
-
if (json !== void 0) return json;
|
|
710
|
-
} catch {
|
|
711
|
-
}
|
|
712
|
-
return String(value);
|
|
556
|
+
function formatLabel(key) {
|
|
557
|
+
return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").trim();
|
|
713
558
|
}
|
|
714
559
|
function renderPopupValue(value) {
|
|
715
|
-
if (value === null || value === void 0)
|
|
716
|
-
return '<span class="zenit-popup-empty">Sin datos</span>';
|
|
717
|
-
}
|
|
560
|
+
if (value === null || value === void 0) return '<span style="color:#94a3b8;">Sin datos</span>';
|
|
718
561
|
if (value instanceof Date) {
|
|
719
|
-
return
|
|
562
|
+
return escapeHtml(value.toLocaleDateString("es-GT"));
|
|
720
563
|
}
|
|
721
564
|
if (typeof value === "number") {
|
|
722
|
-
return
|
|
565
|
+
return escapeHtml(value.toLocaleString("es-GT"));
|
|
723
566
|
}
|
|
724
567
|
if (typeof value === "string") {
|
|
725
568
|
const trimmed = value.trim();
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
return `<span>${escapeHtml(new Date(parsed).toLocaleDateString("es-GT"))}</span>`;
|
|
731
|
-
}
|
|
732
|
-
}
|
|
569
|
+
if (!trimmed) return '<span style="color:#94a3b8;">Sin datos</span>';
|
|
570
|
+
return escapeHtml(trimmed);
|
|
571
|
+
}
|
|
572
|
+
if (typeof value === "object") {
|
|
733
573
|
try {
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
return `<a class="zenit-popup-link" href="${safeHref}" target="_blank" rel="noopener noreferrer">${safeHref}</a>`;
|
|
738
|
-
}
|
|
574
|
+
return `<pre style="margin:0; white-space:pre-wrap; font-size:11px; background:#f8fafc; border:1px solid #e2e8f0; padding:6px 8px; border-radius:6px;">${escapeHtml(
|
|
575
|
+
JSON.stringify(value, null, 2)
|
|
576
|
+
)}</pre>`;
|
|
739
577
|
} catch {
|
|
578
|
+
return escapeHtml(String(value));
|
|
740
579
|
}
|
|
741
|
-
return `<span>${escapeHtml(trimmed || value)}</span>`;
|
|
742
|
-
}
|
|
743
|
-
if (typeof value === "object") {
|
|
744
|
-
const json = safeJsonStringify(value);
|
|
745
|
-
return `<pre class="zenit-popup-pre">${escapeHtml(json)}</pre>`;
|
|
746
580
|
}
|
|
747
|
-
return
|
|
581
|
+
return escapeHtml(String(value));
|
|
582
|
+
}
|
|
583
|
+
function extractPopupHeader(properties) {
|
|
584
|
+
const entry = Object.entries(properties).find(([key, value]) => {
|
|
585
|
+
if (typeof value !== "string") return false;
|
|
586
|
+
const normalized = key.trim().toLowerCase();
|
|
587
|
+
return POPUP_HEADER_KEYS.includes(normalized) && value.trim().length > 0;
|
|
588
|
+
});
|
|
589
|
+
return entry ? entry[1].trim() : null;
|
|
748
590
|
}
|
|
749
591
|
function shouldIncludePopupEntry(key, value) {
|
|
750
592
|
if (!key) return false;
|
|
@@ -756,118 +598,480 @@ function shouldIncludePopupEntry(key, value) {
|
|
|
756
598
|
if (typeof value === "string" && !value.trim()) return false;
|
|
757
599
|
return true;
|
|
758
600
|
}
|
|
759
|
-
function
|
|
760
|
-
const
|
|
761
|
-
|
|
601
|
+
function createPopupContent(properties) {
|
|
602
|
+
const headerText = extractPopupHeader(properties);
|
|
603
|
+
const entries = Object.entries(properties).filter(([key, value]) => {
|
|
604
|
+
if (!shouldIncludePopupEntry(key, value)) return false;
|
|
605
|
+
if (headerText && POPUP_HEADER_KEYS.includes(key.trim().toLowerCase())) return false;
|
|
606
|
+
return true;
|
|
607
|
+
});
|
|
608
|
+
if (entries.length === 0) {
|
|
609
|
+
return '<div style="padding:8px 0; color:#64748b; text-align:center;">Sin datos disponibles</div>';
|
|
610
|
+
}
|
|
611
|
+
const headerHtml = headerText ? `<div style="font-weight:700; font-size:14px; margin-bottom:8px; color:#0f172a;">${escapeHtml(
|
|
612
|
+
headerText
|
|
613
|
+
)}</div>` : "";
|
|
614
|
+
const rowsHtml = entries.map(([key, value]) => {
|
|
615
|
+
const label = escapeHtml(formatLabel(key));
|
|
616
|
+
const valueHtml = renderPopupValue(value);
|
|
617
|
+
return `
|
|
618
|
+
<div style="display:grid; grid-template-columns:minmax(90px, 35%) 1fr; gap:8px; padding:6px 0; border-bottom:1px solid #e2e8f0;">
|
|
619
|
+
<div style="font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.04em; color:#64748b;">${label}</div>
|
|
620
|
+
<div style="font-size:13px; color:#0f172a; word-break:break-word;">${valueHtml}</div>
|
|
621
|
+
</div>
|
|
622
|
+
`;
|
|
623
|
+
}).join("");
|
|
624
|
+
return `<div>${headerHtml}${rowsHtml}</div>`;
|
|
762
625
|
}
|
|
763
|
-
function
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
626
|
+
function isPolygonType(layerType, geometryType) {
|
|
627
|
+
const candidate = (layerType ?? geometryType ?? "").toLowerCase();
|
|
628
|
+
return candidate === "polygon" || candidate === "multipolygon";
|
|
629
|
+
}
|
|
630
|
+
function calculateZoomBasedOpacity(zoom, baseOpacity, layerType, geometryType) {
|
|
631
|
+
if (!isPolygonType(layerType, geometryType)) return clampOpacity4(baseOpacity);
|
|
632
|
+
const minZoom = 11;
|
|
633
|
+
const maxZoom = 15;
|
|
634
|
+
const minFactor = 0.3;
|
|
635
|
+
if (maxZoom <= minZoom) return clampOpacity4(baseOpacity * minFactor);
|
|
636
|
+
const t = clampNumber2((zoom - minZoom) / (maxZoom - minZoom), 0, 1);
|
|
637
|
+
const factor = 1 - (1 - minFactor) * t;
|
|
638
|
+
return clampOpacity4(baseOpacity * factor);
|
|
639
|
+
}
|
|
640
|
+
function layerStyleToLeaflet(options) {
|
|
641
|
+
const { baseOpacity, zoom, layerStyle, geometryType, layerType } = options;
|
|
642
|
+
const sanitizedOpacity = clampOpacity4(baseOpacity);
|
|
643
|
+
const zoomOpacity = calculateZoomBasedOpacity(zoom, sanitizedOpacity, layerType, geometryType);
|
|
644
|
+
const styleFillOpacity = typeof layerStyle?.fillOpacity === "number" ? clampOpacity4(layerStyle.fillOpacity) : 0.8;
|
|
645
|
+
return {
|
|
646
|
+
color: layerStyle?.color ?? layerStyle?.fillColor ?? "#2563eb",
|
|
647
|
+
weight: layerStyle?.weight ?? 2,
|
|
648
|
+
fillColor: layerStyle?.fillColor ?? layerStyle?.color ?? "#2563eb",
|
|
649
|
+
opacity: clampOpacity4(Math.max(0.35, zoomOpacity * 0.9)),
|
|
650
|
+
fillOpacity: clampOpacity4(zoomOpacity * styleFillOpacity)
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function getRgbFromColor(color) {
|
|
654
|
+
const trimmed = color.trim();
|
|
655
|
+
if (trimmed.startsWith("#")) {
|
|
656
|
+
const hex = trimmed.replace("#", "");
|
|
657
|
+
const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
|
|
658
|
+
if (expanded.length === 6) {
|
|
659
|
+
const r = parseInt(expanded.slice(0, 2), 16);
|
|
660
|
+
const g = parseInt(expanded.slice(2, 4), 16);
|
|
661
|
+
const b = parseInt(expanded.slice(4, 6), 16);
|
|
662
|
+
return { r, g, b };
|
|
769
663
|
}
|
|
664
|
+
}
|
|
665
|
+
const rgbMatch = trimmed.match(/rgba?\(([^)]+)\)/i);
|
|
666
|
+
if (rgbMatch) {
|
|
667
|
+
const [r, g, b] = rgbMatch[1].split(",").map((value) => parseFloat(value.trim())).slice(0, 3);
|
|
668
|
+
if ([r, g, b].every((value) => Number.isFinite(value))) {
|
|
669
|
+
return { r, g, b };
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
function getLabelTextStyles(color) {
|
|
675
|
+
const rgb = getRgbFromColor(color);
|
|
676
|
+
if (!rgb) {
|
|
677
|
+
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.6)" };
|
|
678
|
+
}
|
|
679
|
+
const luminance = (0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b) / 255;
|
|
680
|
+
if (luminance > 0.6) {
|
|
681
|
+
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.7)" };
|
|
682
|
+
}
|
|
683
|
+
return { color: "#ffffff", shadow: "0 1px 2px rgba(0, 0, 0, 0.4)" };
|
|
684
|
+
}
|
|
685
|
+
function withAlpha(color, alpha) {
|
|
686
|
+
const trimmed = color.trim();
|
|
687
|
+
if (trimmed.startsWith("#")) {
|
|
688
|
+
const hex = trimmed.replace("#", "");
|
|
689
|
+
const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
|
|
690
|
+
if (expanded.length === 6) {
|
|
691
|
+
const r = parseInt(expanded.slice(0, 2), 16);
|
|
692
|
+
const g = parseInt(expanded.slice(2, 4), 16);
|
|
693
|
+
const b = parseInt(expanded.slice(4, 6), 16);
|
|
694
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
if (trimmed.startsWith("rgb(")) {
|
|
698
|
+
const inner = trimmed.slice(4, -1);
|
|
699
|
+
return `rgba(${inner}, ${alpha})`;
|
|
700
|
+
}
|
|
701
|
+
if (trimmed.startsWith("rgba(")) {
|
|
702
|
+
const inner = trimmed.slice(5, -1).split(",").slice(0, 3).map((value) => value.trim());
|
|
703
|
+
return `rgba(${inner.join(", ")}, ${alpha})`;
|
|
704
|
+
}
|
|
705
|
+
return color;
|
|
706
|
+
}
|
|
707
|
+
function createCustomIcon(label, opacity, color) {
|
|
708
|
+
const size = 60;
|
|
709
|
+
const innerSize = 44;
|
|
710
|
+
const textStyles = getLabelTextStyles(color);
|
|
711
|
+
const safeLabel = escapeHtml(label);
|
|
712
|
+
const clampedOpacity = Math.min(1, Math.max(0.92, opacity));
|
|
713
|
+
const innerBackground = withAlpha(color, 0.9);
|
|
714
|
+
return import_leaflet2.default.divIcon({
|
|
715
|
+
className: "zenit-label-marker",
|
|
716
|
+
iconSize: [size, size],
|
|
717
|
+
iconAnchor: [size / 2, size / 2],
|
|
718
|
+
html: `
|
|
719
|
+
<div
|
|
720
|
+
title="${safeLabel}"
|
|
721
|
+
style="
|
|
722
|
+
width:${size}px;
|
|
723
|
+
height:${size}px;
|
|
724
|
+
border-radius:9999px;
|
|
725
|
+
background:rgba(255, 255, 255, 0.95);
|
|
726
|
+
border:3px solid rgba(255, 255, 255, 1);
|
|
727
|
+
display:flex;
|
|
728
|
+
align-items:center;
|
|
729
|
+
justify-content:center;
|
|
730
|
+
opacity:${clampedOpacity};
|
|
731
|
+
box-shadow:0 2px 6px rgba(0, 0, 0, 0.25);
|
|
732
|
+
pointer-events:none;
|
|
733
|
+
"
|
|
734
|
+
>
|
|
735
|
+
<div
|
|
736
|
+
style="
|
|
737
|
+
width:${innerSize}px;
|
|
738
|
+
height:${innerSize}px;
|
|
739
|
+
border-radius:9999px;
|
|
740
|
+
background:${innerBackground};
|
|
741
|
+
display:flex;
|
|
742
|
+
align-items:center;
|
|
743
|
+
justify-content:center;
|
|
744
|
+
box-shadow:inset 0 0 0 1px rgba(15, 23, 42, 0.12);
|
|
745
|
+
"
|
|
746
|
+
>
|
|
747
|
+
<span
|
|
748
|
+
style="
|
|
749
|
+
color:${textStyles.color};
|
|
750
|
+
font-size:20px;
|
|
751
|
+
font-weight:800;
|
|
752
|
+
text-shadow:${textStyles.shadow};
|
|
753
|
+
"
|
|
754
|
+
>
|
|
755
|
+
${safeLabel}
|
|
756
|
+
</span>
|
|
757
|
+
</div>
|
|
758
|
+
</div>
|
|
759
|
+
`
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
function createLocationIcon() {
|
|
763
|
+
return import_leaflet2.default.divIcon({
|
|
764
|
+
className: "zenit-location-marker",
|
|
765
|
+
iconSize: [18, 18],
|
|
766
|
+
iconAnchor: [9, 9],
|
|
767
|
+
html: `
|
|
768
|
+
<div style="width:18px;height:18px;border-radius:9999px;background:#2563eb;border:2px solid #fff;box-shadow:0 0 0 4px rgba(37, 99, 235, 0.25);"></div>
|
|
769
|
+
`
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// src/react/map/location-control.tsx
|
|
774
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
775
|
+
var LOCATION_STYLE_ID = "zenit-location-control-styles";
|
|
776
|
+
var LOCATION_STYLES = `
|
|
777
|
+
.zenit-location-control {
|
|
778
|
+
display: flex;
|
|
779
|
+
flex-direction: column;
|
|
780
|
+
gap: 8px;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.zenit-location-button {
|
|
784
|
+
width: 42px;
|
|
785
|
+
height: 42px;
|
|
786
|
+
border-radius: 12px;
|
|
787
|
+
border: none;
|
|
788
|
+
background: #ffffff;
|
|
789
|
+
color: #0f172a;
|
|
790
|
+
box-shadow: 0 8px 18px rgba(15, 23, 42, 0.2);
|
|
791
|
+
display: inline-flex;
|
|
792
|
+
align-items: center;
|
|
793
|
+
justify-content: center;
|
|
794
|
+
cursor: pointer;
|
|
795
|
+
position: relative;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
.zenit-location-button.zenit-location-button--tracking {
|
|
799
|
+
animation: zenitLocationPulse 1.8s infinite;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
.zenit-location-button:hover {
|
|
803
|
+
background: #f8fafc;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.zenit-location-badge {
|
|
807
|
+
position: absolute;
|
|
808
|
+
top: -6px;
|
|
809
|
+
right: -6px;
|
|
810
|
+
width: 18px;
|
|
811
|
+
height: 18px;
|
|
812
|
+
border-radius: 999px;
|
|
813
|
+
background: #ef4444;
|
|
814
|
+
color: #fff;
|
|
815
|
+
font-size: 11px;
|
|
816
|
+
font-weight: 700;
|
|
817
|
+
display: inline-flex;
|
|
818
|
+
align-items: center;
|
|
819
|
+
justify-content: center;
|
|
820
|
+
box-shadow: 0 4px 10px rgba(239, 68, 68, 0.35);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
.zenit-location-error {
|
|
824
|
+
background: rgba(15, 23, 42, 0.92);
|
|
825
|
+
color: #f8fafc;
|
|
826
|
+
border-radius: 10px;
|
|
827
|
+
padding: 8px 10px;
|
|
828
|
+
font-size: 12px;
|
|
829
|
+
max-width: 200px;
|
|
830
|
+
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.3);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
@keyframes zenitLocationPulse {
|
|
834
|
+
0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.35); }
|
|
835
|
+
70% { box-shadow: 0 0 0 12px rgba(16, 185, 129, 0); }
|
|
836
|
+
100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
|
|
837
|
+
}
|
|
838
|
+
`;
|
|
839
|
+
var LocateIcon = () => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
840
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "3" }),
|
|
841
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "2", x2: "12", y2: "5" }),
|
|
842
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "19", x2: "12", y2: "22" }),
|
|
843
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "2", y1: "12", x2: "5", y2: "12" }),
|
|
844
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "19", y1: "12", x2: "22", y2: "12" })
|
|
845
|
+
] });
|
|
846
|
+
var LocationControl = ({ position = "bottomleft", zoom = 16 }) => {
|
|
847
|
+
const map = (0, import_react_leaflet2.useMap)();
|
|
848
|
+
const controlRef = (0, import_react2.useRef)(null);
|
|
849
|
+
const hasCenteredRef = (0, import_react2.useRef)(false);
|
|
850
|
+
const { isTracking, location, error, toggleTracking, clearError } = useGeolocation();
|
|
851
|
+
(0, import_react2.useEffect)(() => {
|
|
852
|
+
if (typeof document === "undefined") return;
|
|
853
|
+
if (document.getElementById(LOCATION_STYLE_ID)) return;
|
|
854
|
+
const styleTag = document.createElement("style");
|
|
855
|
+
styleTag.id = LOCATION_STYLE_ID;
|
|
856
|
+
styleTag.textContent = LOCATION_STYLES;
|
|
857
|
+
document.head.appendChild(styleTag);
|
|
858
|
+
}, []);
|
|
859
|
+
(0, import_react2.useEffect)(() => {
|
|
860
|
+
const control = import_leaflet3.default.control({ position });
|
|
861
|
+
control.onAdd = () => {
|
|
862
|
+
const container = import_leaflet3.default.DomUtil.create("div", "zenit-location-control");
|
|
863
|
+
import_leaflet3.default.DomEvent.disableClickPropagation(container);
|
|
864
|
+
controlRef.current = container;
|
|
865
|
+
return container;
|
|
866
|
+
};
|
|
867
|
+
control.addTo(map);
|
|
868
|
+
return () => {
|
|
869
|
+
control.remove();
|
|
870
|
+
controlRef.current = null;
|
|
871
|
+
};
|
|
872
|
+
}, [map, position]);
|
|
873
|
+
(0, import_react2.useEffect)(() => {
|
|
874
|
+
if (!location || !isTracking) return;
|
|
875
|
+
if (hasCenteredRef.current) return;
|
|
876
|
+
hasCenteredRef.current = true;
|
|
877
|
+
map.flyTo([location.lat, location.lon], zoom, { animate: true });
|
|
878
|
+
}, [isTracking, location, map, zoom]);
|
|
879
|
+
const markerIcon = (0, import_react2.useMemo)(() => createLocationIcon(), []);
|
|
880
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
881
|
+
controlRef.current && (0, import_react_dom.createPortal)(
|
|
882
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
883
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
884
|
+
"button",
|
|
885
|
+
{
|
|
886
|
+
type: "button",
|
|
887
|
+
className: `zenit-location-button${isTracking ? " zenit-location-button--tracking" : ""}`,
|
|
888
|
+
onClick: () => {
|
|
889
|
+
if (error) {
|
|
890
|
+
clearError();
|
|
891
|
+
}
|
|
892
|
+
toggleTracking();
|
|
893
|
+
},
|
|
894
|
+
"aria-label": isTracking ? "Detener ubicaci\xF3n" : "Mostrar mi ubicaci\xF3n",
|
|
895
|
+
children: [
|
|
896
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LocateIcon, {}),
|
|
897
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "zenit-location-badge", children: "!" })
|
|
898
|
+
]
|
|
899
|
+
}
|
|
900
|
+
),
|
|
901
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "zenit-location-error", children: error.message || "No se pudo acceder a tu ubicaci\xF3n." })
|
|
902
|
+
] }),
|
|
903
|
+
controlRef.current
|
|
904
|
+
),
|
|
905
|
+
location && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
906
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_leaflet2.Marker, { position: [location.lat, location.lon], icon: markerIcon }),
|
|
907
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
908
|
+
import_react_leaflet2.Circle,
|
|
909
|
+
{
|
|
910
|
+
center: [location.lat, location.lon],
|
|
911
|
+
radius: location.accuracy,
|
|
912
|
+
pathOptions: { color: "#2563eb", fillColor: "#2563eb", fillOpacity: 0.15 }
|
|
913
|
+
}
|
|
914
|
+
)
|
|
915
|
+
] })
|
|
916
|
+
] });
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
// src/react/map/map-handlers.tsx
|
|
920
|
+
var import_react3 = require("react");
|
|
921
|
+
var import_react_leaflet3 = require("react-leaflet");
|
|
922
|
+
function computeBBoxFromGeojson(geojson) {
|
|
923
|
+
if (!geojson || !Array.isArray(geojson.features)) return null;
|
|
924
|
+
const coords = [];
|
|
925
|
+
const collect = (candidate) => {
|
|
926
|
+
if (!Array.isArray(candidate)) return;
|
|
927
|
+
if (candidate.length === 2 && typeof candidate[0] === "number" && typeof candidate[1] === "number" && Number.isFinite(candidate[0]) && Number.isFinite(candidate[1])) {
|
|
928
|
+
coords.push([candidate[0], candidate[1]]);
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
candidate.forEach((item) => collect(item));
|
|
932
|
+
};
|
|
933
|
+
geojson.features.forEach((feature) => {
|
|
934
|
+
collect(feature.geometry?.coordinates);
|
|
935
|
+
});
|
|
936
|
+
if (coords.length === 0) return null;
|
|
937
|
+
const [firstLon, firstLat] = coords[0];
|
|
938
|
+
const bbox = { minLon: firstLon, minLat: firstLat, maxLon: firstLon, maxLat: firstLat };
|
|
939
|
+
coords.forEach(([lon, lat]) => {
|
|
940
|
+
bbox.minLon = Math.min(bbox.minLon, lon);
|
|
941
|
+
bbox.minLat = Math.min(bbox.minLat, lat);
|
|
942
|
+
bbox.maxLon = Math.max(bbox.maxLon, lon);
|
|
943
|
+
bbox.maxLat = Math.max(bbox.maxLat, lat);
|
|
944
|
+
});
|
|
945
|
+
return bbox;
|
|
946
|
+
}
|
|
947
|
+
function mergeBBoxes(bboxes) {
|
|
948
|
+
const valid = bboxes.filter((bbox) => !!bbox);
|
|
949
|
+
if (valid.length === 0) return null;
|
|
950
|
+
const first = valid[0];
|
|
951
|
+
return valid.slice(1).reduce(
|
|
952
|
+
(acc, bbox) => ({
|
|
953
|
+
minLon: Math.min(acc.minLon, bbox.minLon),
|
|
954
|
+
minLat: Math.min(acc.minLat, bbox.minLat),
|
|
955
|
+
maxLon: Math.max(acc.maxLon, bbox.maxLon),
|
|
956
|
+
maxLat: Math.max(acc.maxLat, bbox.maxLat)
|
|
957
|
+
}),
|
|
958
|
+
{ ...first }
|
|
770
959
|
);
|
|
771
|
-
if (!entry) return null;
|
|
772
|
-
return entry[1].trim();
|
|
773
960
|
}
|
|
774
|
-
|
|
775
|
-
|
|
961
|
+
var BBoxZoomHandler = ({
|
|
962
|
+
bbox,
|
|
963
|
+
geojson,
|
|
964
|
+
autoGeojson = [],
|
|
965
|
+
enabled = true
|
|
966
|
+
}) => {
|
|
967
|
+
const map = (0, import_react_leaflet3.useMap)();
|
|
968
|
+
const lastAppliedBBox = (0, import_react3.useRef)(null);
|
|
969
|
+
const lastUserInteracted = (0, import_react3.useRef)(false);
|
|
970
|
+
(0, import_react3.useEffect)(() => {
|
|
971
|
+
const handleInteraction = () => {
|
|
972
|
+
lastUserInteracted.current = true;
|
|
973
|
+
};
|
|
974
|
+
map.on("dragstart", handleInteraction);
|
|
975
|
+
map.on("zoomstart", handleInteraction);
|
|
976
|
+
return () => {
|
|
977
|
+
map.off("dragstart", handleInteraction);
|
|
978
|
+
map.off("zoomstart", handleInteraction);
|
|
979
|
+
};
|
|
980
|
+
}, [map]);
|
|
981
|
+
(0, import_react3.useEffect)(() => {
|
|
982
|
+
if (!enabled) return;
|
|
983
|
+
let resolvedBBox = bbox ?? null;
|
|
984
|
+
if (!resolvedBBox && geojson) {
|
|
985
|
+
resolvedBBox = computeBBoxFromGeojson(geojson);
|
|
986
|
+
}
|
|
987
|
+
if (!resolvedBBox && autoGeojson.length > 0) {
|
|
988
|
+
const bboxes = autoGeojson.map((collection) => computeBBoxFromGeojson(collection));
|
|
989
|
+
resolvedBBox = mergeBBoxes(bboxes);
|
|
990
|
+
}
|
|
991
|
+
if (!resolvedBBox) return;
|
|
992
|
+
const serialized = JSON.stringify(resolvedBBox);
|
|
993
|
+
if (lastAppliedBBox.current === serialized) return;
|
|
994
|
+
if (lastUserInteracted.current && !bbox && !geojson) {
|
|
995
|
+
lastUserInteracted.current = false;
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
const bounds = [
|
|
999
|
+
[resolvedBBox.minLat, resolvedBBox.minLon],
|
|
1000
|
+
[resolvedBBox.maxLat, resolvedBBox.maxLon]
|
|
1001
|
+
];
|
|
1002
|
+
map.fitBounds(bounds, { padding: [12, 12] });
|
|
1003
|
+
lastAppliedBBox.current = serialized;
|
|
1004
|
+
}, [autoGeojson, bbox, enabled, geojson, map]);
|
|
1005
|
+
return null;
|
|
1006
|
+
};
|
|
1007
|
+
var ZoomBasedOpacityHandler = ({ onZoomChange }) => {
|
|
1008
|
+
const map = (0, import_react_leaflet3.useMap)();
|
|
1009
|
+
(0, import_react3.useEffect)(() => {
|
|
1010
|
+
const handleZoom = () => {
|
|
1011
|
+
onZoomChange(map.getZoom());
|
|
1012
|
+
};
|
|
1013
|
+
map.on("zoomend", handleZoom);
|
|
1014
|
+
handleZoom();
|
|
1015
|
+
return () => {
|
|
1016
|
+
map.off("zoomend", handleZoom);
|
|
1017
|
+
};
|
|
1018
|
+
}, [map, onZoomChange]);
|
|
1019
|
+
return null;
|
|
1020
|
+
};
|
|
1021
|
+
var MapInstanceBridge = ({ onReady }) => {
|
|
1022
|
+
const map = (0, import_react_leaflet3.useMap)();
|
|
1023
|
+
(0, import_react3.useEffect)(() => {
|
|
1024
|
+
onReady(map);
|
|
1025
|
+
}, [map, onReady]);
|
|
1026
|
+
return null;
|
|
1027
|
+
};
|
|
1028
|
+
|
|
1029
|
+
// src/react/ZenitMap.tsx
|
|
1030
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1031
|
+
var DEFAULT_CENTER = [0, 0];
|
|
1032
|
+
var DEFAULT_ZOOM = 3;
|
|
1033
|
+
var LABELS_PANE_NAME = "zenit-labels-pane";
|
|
1034
|
+
function isRecord(value) {
|
|
1035
|
+
return typeof value === "object" && value !== null;
|
|
1036
|
+
}
|
|
1037
|
+
function isGeoJsonFeatureCollection(value) {
|
|
1038
|
+
if (!isRecord(value)) return false;
|
|
1039
|
+
const features = value.features;
|
|
1040
|
+
if (!Array.isArray(features)) return false;
|
|
1041
|
+
const type = value.type;
|
|
1042
|
+
return type === void 0 || type === "FeatureCollection";
|
|
776
1043
|
}
|
|
777
|
-
function
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
if (headerText && POPUP_HEADER_KEYS.includes(key.trim().toLowerCase())) {
|
|
782
|
-
return false;
|
|
783
|
-
}
|
|
784
|
-
return true;
|
|
785
|
-
});
|
|
786
|
-
if (entries.length === 0) {
|
|
787
|
-
return `<div class="zenit-popup-card"><div class="zenit-popup-empty">Sin datos disponibles</div></div>`;
|
|
788
|
-
}
|
|
789
|
-
const descriptionEntry = entries.find(([key]) => isDescriptionKey(key));
|
|
790
|
-
const otherEntries = entries.filter(([key]) => !isDescriptionKey(key));
|
|
791
|
-
let rowsHtml = "";
|
|
792
|
-
if (descriptionEntry) {
|
|
793
|
-
const [key, value] = descriptionEntry;
|
|
794
|
-
const label = escapeHtml(formatLabel(key));
|
|
795
|
-
const valueHtml = renderPopupValue(value);
|
|
796
|
-
rowsHtml += `
|
|
797
|
-
<div class="zenit-popup-row zenit-popup-description">
|
|
798
|
-
<div class="zenit-popup-label">${label}</div>
|
|
799
|
-
<div class="zenit-popup-value">${valueHtml}</div>
|
|
800
|
-
</div>
|
|
801
|
-
`;
|
|
1044
|
+
function extractGeoJsonFeatureCollection(value) {
|
|
1045
|
+
if (isRecord(value) && "data" in value) {
|
|
1046
|
+
const data = value.data;
|
|
1047
|
+
return isGeoJsonFeatureCollection(data) ? data : null;
|
|
802
1048
|
}
|
|
803
|
-
|
|
804
|
-
const label = escapeHtml(formatLabel(key));
|
|
805
|
-
const valueHtml = renderPopupValue(value);
|
|
806
|
-
return `
|
|
807
|
-
<div class="zenit-popup-row">
|
|
808
|
-
<div class="zenit-popup-label">${label}</div>
|
|
809
|
-
<div class="zenit-popup-value">${valueHtml}</div>
|
|
810
|
-
</div>
|
|
811
|
-
`;
|
|
812
|
-
}).join("");
|
|
813
|
-
const headerHtml = headerText ? `<div class="zenit-popup-header"><div class="zenit-popup-title">${escapeHtml(
|
|
814
|
-
headerText
|
|
815
|
-
)}</div></div>` : "";
|
|
816
|
-
return `<div class="zenit-popup-card">${headerHtml}${rowsHtml}</div>`;
|
|
1049
|
+
return isGeoJsonFeatureCollection(value) ? value : null;
|
|
817
1050
|
}
|
|
818
|
-
function
|
|
819
|
-
const
|
|
820
|
-
if (
|
|
821
|
-
|
|
822
|
-
const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
|
|
823
|
-
if (expanded.length === 6) {
|
|
824
|
-
const r = parseInt(expanded.slice(0, 2), 16);
|
|
825
|
-
const g = parseInt(expanded.slice(2, 4), 16);
|
|
826
|
-
const b = parseInt(expanded.slice(4, 6), 16);
|
|
827
|
-
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
if (trimmed.startsWith("rgb(")) {
|
|
831
|
-
const inner = trimmed.slice(4, -1);
|
|
832
|
-
return `rgba(${inner}, ${alpha})`;
|
|
833
|
-
}
|
|
834
|
-
if (trimmed.startsWith("rgba(")) {
|
|
835
|
-
const inner = trimmed.slice(5, -1).split(",").slice(0, 3).map((value) => value.trim());
|
|
836
|
-
return `rgba(${inner.join(", ")}, ${alpha})`;
|
|
837
|
-
}
|
|
838
|
-
return color;
|
|
1051
|
+
function getFeatureLayerId(feature) {
|
|
1052
|
+
const layerId = feature?.properties?.__zenit_layerId ?? feature?.properties?.layerId ?? feature?.properties?.layer_id;
|
|
1053
|
+
if (layerId === void 0 || layerId === null) return null;
|
|
1054
|
+
return layerId;
|
|
839
1055
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
if (
|
|
843
|
-
|
|
844
|
-
const
|
|
845
|
-
|
|
846
|
-
const r = parseInt(expanded.slice(0, 2), 16);
|
|
847
|
-
const g = parseInt(expanded.slice(2, 4), 16);
|
|
848
|
-
const b = parseInt(expanded.slice(4, 6), 16);
|
|
849
|
-
return { r, g, b };
|
|
850
|
-
}
|
|
1056
|
+
var DESCRIPTION_KEYS = /* @__PURE__ */ new Set(["descripcion", "description"]);
|
|
1057
|
+
function normalizeDescriptionValue(value) {
|
|
1058
|
+
if (value === void 0 || value === null) return null;
|
|
1059
|
+
if (typeof value === "string") {
|
|
1060
|
+
const trimmed = value.trim();
|
|
1061
|
+
return trimmed ? trimmed : null;
|
|
851
1062
|
}
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
const [r, g, b] = rgbMatch[1].split(",").map((value) => parseFloat(value.trim())).slice(0, 3);
|
|
855
|
-
if ([r, g, b].every((value) => Number.isFinite(value))) {
|
|
856
|
-
return { r, g, b };
|
|
857
|
-
}
|
|
1063
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
1064
|
+
return String(value);
|
|
858
1065
|
}
|
|
859
1066
|
return null;
|
|
860
1067
|
}
|
|
861
|
-
function
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.7)" };
|
|
869
|
-
}
|
|
870
|
-
return { color: "#ffffff", shadow: "0 1px 2px rgba(0, 0, 0, 0.4)" };
|
|
1068
|
+
function extractDescriptionValue(properties) {
|
|
1069
|
+
if (!properties) return null;
|
|
1070
|
+
const matches = Object.entries(properties).find(
|
|
1071
|
+
([key]) => DESCRIPTION_KEYS.has(key.toLowerCase())
|
|
1072
|
+
);
|
|
1073
|
+
if (!matches) return null;
|
|
1074
|
+
return normalizeDescriptionValue(matches[1]);
|
|
871
1075
|
}
|
|
872
1076
|
function getFeatureStyleOverrides(feature) {
|
|
873
1077
|
const candidate = feature?.properties?._style;
|
|
@@ -886,25 +1090,6 @@ function buildFeaturePopupHtml(feature) {
|
|
|
886
1090
|
const rendered = createPopupContent(properties);
|
|
887
1091
|
return rendered ? rendered : null;
|
|
888
1092
|
}
|
|
889
|
-
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
890
|
-
function getGeometryType(feature) {
|
|
891
|
-
const t = feature?.geometry?.type;
|
|
892
|
-
return typeof t === "string" ? t : null;
|
|
893
|
-
}
|
|
894
|
-
function isPointGeometry(feature) {
|
|
895
|
-
const geometryType = getGeometryType(feature);
|
|
896
|
-
return geometryType !== null && POINT_GEOMETRY_TYPES.has(geometryType);
|
|
897
|
-
}
|
|
898
|
-
function isNonPointGeometry(feature) {
|
|
899
|
-
const geometryType = getGeometryType(feature);
|
|
900
|
-
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
901
|
-
}
|
|
902
|
-
function buildFeatureCollection(features) {
|
|
903
|
-
return {
|
|
904
|
-
type: "FeatureCollection",
|
|
905
|
-
features
|
|
906
|
-
};
|
|
907
|
-
}
|
|
908
1093
|
function pickIntersectFeature(baseFeature, candidates) {
|
|
909
1094
|
if (!Array.isArray(candidates) || candidates.length === 0) return null;
|
|
910
1095
|
const baseId = baseFeature?.id;
|
|
@@ -931,81 +1116,7 @@ function normalizeCenterTuple(center) {
|
|
|
931
1116
|
}
|
|
932
1117
|
return null;
|
|
933
1118
|
}
|
|
934
|
-
var
|
|
935
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
936
|
-
const lastAppliedBBox = (0, import_react.useRef)(null);
|
|
937
|
-
(0, import_react.useEffect)(() => {
|
|
938
|
-
const targetBBox = bbox;
|
|
939
|
-
if (!targetBBox) return;
|
|
940
|
-
const serialized = JSON.stringify(targetBBox);
|
|
941
|
-
if (lastAppliedBBox.current === serialized) return;
|
|
942
|
-
const bounds = [
|
|
943
|
-
[targetBBox.minLat, targetBBox.minLon],
|
|
944
|
-
[targetBBox.maxLat, targetBBox.maxLon]
|
|
945
|
-
];
|
|
946
|
-
mapInstance.fitBounds(bounds, { padding: [12, 12] });
|
|
947
|
-
lastAppliedBBox.current = serialized;
|
|
948
|
-
}, [bbox, mapInstance]);
|
|
949
|
-
return null;
|
|
950
|
-
};
|
|
951
|
-
var AutoFitToBounds = ({
|
|
952
|
-
bbox,
|
|
953
|
-
enabled = true
|
|
954
|
-
}) => {
|
|
955
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
956
|
-
const lastAutoBBoxApplied = (0, import_react.useRef)(null);
|
|
957
|
-
const lastUserInteracted = (0, import_react.useRef)(false);
|
|
958
|
-
(0, import_react.useEffect)(() => {
|
|
959
|
-
if (!enabled) return;
|
|
960
|
-
const handleInteraction = () => {
|
|
961
|
-
lastUserInteracted.current = true;
|
|
962
|
-
};
|
|
963
|
-
mapInstance.on("dragstart", handleInteraction);
|
|
964
|
-
mapInstance.on("zoomstart", handleInteraction);
|
|
965
|
-
return () => {
|
|
966
|
-
mapInstance.off("dragstart", handleInteraction);
|
|
967
|
-
mapInstance.off("zoomstart", handleInteraction);
|
|
968
|
-
};
|
|
969
|
-
}, [enabled, mapInstance]);
|
|
970
|
-
(0, import_react.useEffect)(() => {
|
|
971
|
-
if (!enabled) return;
|
|
972
|
-
if (!bbox) return;
|
|
973
|
-
const serialized = JSON.stringify(bbox);
|
|
974
|
-
if (lastAutoBBoxApplied.current === serialized) return;
|
|
975
|
-
if (lastUserInteracted.current) {
|
|
976
|
-
lastUserInteracted.current = false;
|
|
977
|
-
}
|
|
978
|
-
const bounds = [
|
|
979
|
-
[bbox.minLat, bbox.minLon],
|
|
980
|
-
[bbox.maxLat, bbox.maxLon]
|
|
981
|
-
];
|
|
982
|
-
mapInstance.fitBounds(bounds, { padding: [12, 12] });
|
|
983
|
-
lastAutoBBoxApplied.current = serialized;
|
|
984
|
-
}, [bbox, enabled, mapInstance]);
|
|
985
|
-
return null;
|
|
986
|
-
};
|
|
987
|
-
var ZoomBasedOpacityHandler = ({ onZoomChange }) => {
|
|
988
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
989
|
-
(0, import_react.useEffect)(() => {
|
|
990
|
-
const handleZoom = () => {
|
|
991
|
-
onZoomChange(mapInstance.getZoom());
|
|
992
|
-
};
|
|
993
|
-
mapInstance.on("zoomend", handleZoom);
|
|
994
|
-
handleZoom();
|
|
995
|
-
return () => {
|
|
996
|
-
mapInstance.off("zoomend", handleZoom);
|
|
997
|
-
};
|
|
998
|
-
}, [mapInstance, onZoomChange]);
|
|
999
|
-
return null;
|
|
1000
|
-
};
|
|
1001
|
-
var MapInstanceBridge = ({ onReady }) => {
|
|
1002
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
1003
|
-
(0, import_react.useEffect)(() => {
|
|
1004
|
-
onReady(mapInstance);
|
|
1005
|
-
}, [mapInstance, onReady]);
|
|
1006
|
-
return null;
|
|
1007
|
-
};
|
|
1008
|
-
var ZenitMap = (0, import_react.forwardRef)(({
|
|
1119
|
+
var ZenitMap = (0, import_react4.forwardRef)(({
|
|
1009
1120
|
client,
|
|
1010
1121
|
mapId,
|
|
1011
1122
|
height = "500px",
|
|
@@ -1030,21 +1141,21 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1030
1141
|
onZoomChange,
|
|
1031
1142
|
onMapReady
|
|
1032
1143
|
}, ref) => {
|
|
1033
|
-
const [map, setMap] = (0,
|
|
1034
|
-
const [layers, setLayers] = (0,
|
|
1035
|
-
const [effectiveStates, setEffectiveStates] = (0,
|
|
1036
|
-
const [loadingMap, setLoadingMap] = (0,
|
|
1037
|
-
const [mapError, setMapError] = (0,
|
|
1038
|
-
const [mapInstance, setMapInstance] = (0,
|
|
1039
|
-
const [panesReady, setPanesReady] = (0,
|
|
1040
|
-
const [currentZoom, setCurrentZoom] = (0,
|
|
1041
|
-
const [isPopupOpen, setIsPopupOpen] = (0,
|
|
1042
|
-
const [isMobile, setIsMobile] = (0,
|
|
1144
|
+
const [map, setMap] = (0, import_react4.useState)(null);
|
|
1145
|
+
const [layers, setLayers] = (0, import_react4.useState)([]);
|
|
1146
|
+
const [effectiveStates, setEffectiveStates] = (0, import_react4.useState)([]);
|
|
1147
|
+
const [loadingMap, setLoadingMap] = (0, import_react4.useState)(false);
|
|
1148
|
+
const [mapError, setMapError] = (0, import_react4.useState)(null);
|
|
1149
|
+
const [mapInstance, setMapInstance] = (0, import_react4.useState)(null);
|
|
1150
|
+
const [panesReady, setPanesReady] = (0, import_react4.useState)(false);
|
|
1151
|
+
const [currentZoom, setCurrentZoom] = (0, import_react4.useState)(initialZoom ?? DEFAULT_ZOOM);
|
|
1152
|
+
const [isPopupOpen, setIsPopupOpen] = (0, import_react4.useState)(false);
|
|
1153
|
+
const [isMobile, setIsMobile] = (0, import_react4.useState)(() => {
|
|
1043
1154
|
if (typeof window === "undefined") return false;
|
|
1044
1155
|
return window.matchMedia("(max-width: 768px)").matches;
|
|
1045
1156
|
});
|
|
1046
|
-
const normalizedLayers = (0,
|
|
1047
|
-
(0,
|
|
1157
|
+
const normalizedLayers = (0, import_react4.useMemo)(() => normalizeMapLayers(map), [map]);
|
|
1158
|
+
(0, import_react4.useEffect)(() => {
|
|
1048
1159
|
if (typeof window === "undefined") return;
|
|
1049
1160
|
const mql = window.matchMedia("(max-width: 768px)");
|
|
1050
1161
|
const onChange = (e) => {
|
|
@@ -1062,17 +1173,17 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1062
1173
|
}
|
|
1063
1174
|
return;
|
|
1064
1175
|
}, []);
|
|
1065
|
-
(0,
|
|
1176
|
+
(0, import_react4.useEffect)(() => {
|
|
1066
1177
|
if (featureInfoMode === "popup") {
|
|
1067
1178
|
ensurePopupStyles();
|
|
1068
1179
|
}
|
|
1069
1180
|
}, [featureInfoMode]);
|
|
1070
|
-
(0,
|
|
1181
|
+
(0, import_react4.useEffect)(() => {
|
|
1071
1182
|
if (featureInfoMode !== "popup") {
|
|
1072
1183
|
setIsPopupOpen(false);
|
|
1073
1184
|
}
|
|
1074
1185
|
}, [featureInfoMode]);
|
|
1075
|
-
(0,
|
|
1186
|
+
(0, import_react4.useEffect)(() => {
|
|
1076
1187
|
if (!mapInstance) return;
|
|
1077
1188
|
const popupPane = mapInstance.getPane("popupPane");
|
|
1078
1189
|
if (popupPane) {
|
|
@@ -1081,7 +1192,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1081
1192
|
const labelsPane = mapInstance.getPane(LABELS_PANE_NAME) ?? mapInstance.createPane(LABELS_PANE_NAME);
|
|
1082
1193
|
labelsPane.style.zIndex = "600";
|
|
1083
1194
|
}, [mapInstance]);
|
|
1084
|
-
(0,
|
|
1195
|
+
(0, import_react4.useEffect)(() => {
|
|
1085
1196
|
if (!mapInstance) return;
|
|
1086
1197
|
const handlePopupOpen = () => setIsPopupOpen(true);
|
|
1087
1198
|
const handlePopupClose = () => setIsPopupOpen(false);
|
|
@@ -1092,7 +1203,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1092
1203
|
mapInstance.off("popupclose", handlePopupClose);
|
|
1093
1204
|
};
|
|
1094
1205
|
}, [mapInstance]);
|
|
1095
|
-
const layerStyleIndex = (0,
|
|
1206
|
+
const layerStyleIndex = (0, import_react4.useMemo)(() => {
|
|
1096
1207
|
const index = /* @__PURE__ */ new Map();
|
|
1097
1208
|
(map?.mapLayers ?? []).forEach((entry) => {
|
|
1098
1209
|
const layerStyle = entry.layer?.style ?? entry.mapLayer?.layer?.style ?? entry.style ?? null;
|
|
@@ -1103,7 +1214,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1103
1214
|
});
|
|
1104
1215
|
return index;
|
|
1105
1216
|
}, [map]);
|
|
1106
|
-
const labelKeyIndex = (0,
|
|
1217
|
+
const labelKeyIndex = (0, import_react4.useMemo)(() => {
|
|
1107
1218
|
const index = /* @__PURE__ */ new Map();
|
|
1108
1219
|
normalizedLayers.forEach((entry) => {
|
|
1109
1220
|
const label = entry.layer?.label ?? entry.mapLayer?.label ?? entry.mapLayer.layerConfig?.label;
|
|
@@ -1113,7 +1224,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1113
1224
|
});
|
|
1114
1225
|
return index;
|
|
1115
1226
|
}, [normalizedLayers]);
|
|
1116
|
-
const layerMetaIndex = (0,
|
|
1227
|
+
const layerMetaIndex = (0, import_react4.useMemo)(() => {
|
|
1117
1228
|
const index = /* @__PURE__ */ new Map();
|
|
1118
1229
|
normalizedLayers.forEach((entry) => {
|
|
1119
1230
|
index.set(String(entry.layerId), {
|
|
@@ -1123,7 +1234,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1123
1234
|
});
|
|
1124
1235
|
return index;
|
|
1125
1236
|
}, [normalizedLayers]);
|
|
1126
|
-
const overlayStyleFunction = (0,
|
|
1237
|
+
const overlayStyleFunction = (0, import_react4.useMemo)(() => {
|
|
1127
1238
|
return (feature) => {
|
|
1128
1239
|
const featureLayerId = getFeatureLayerId(feature);
|
|
1129
1240
|
const featureStyleOverrides = getFeatureStyleOverrides(feature);
|
|
@@ -1142,11 +1253,15 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1142
1253
|
return defaultOptions;
|
|
1143
1254
|
};
|
|
1144
1255
|
}, [layerStyleIndex, mapLayers, overlayStyle]);
|
|
1145
|
-
const
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
(0,
|
|
1256
|
+
const overlayStyleFn = (0, import_react4.useCallback)(
|
|
1257
|
+
(feature, _layerType, _baseOpacity) => overlayStyleFunction(feature),
|
|
1258
|
+
[overlayStyleFunction]
|
|
1259
|
+
);
|
|
1260
|
+
const [baseStates, setBaseStates] = (0, import_react4.useState)([]);
|
|
1261
|
+
const [mapOverrides, setMapOverrides] = (0, import_react4.useState)([]);
|
|
1262
|
+
const [controlOverrides, setControlOverrides] = (0, import_react4.useState)([]);
|
|
1263
|
+
const [uiOverrides, setUiOverrides] = (0, import_react4.useState)([]);
|
|
1264
|
+
(0, import_react4.useEffect)(() => {
|
|
1150
1265
|
let isMounted = true;
|
|
1151
1266
|
setLoadingMap(true);
|
|
1152
1267
|
setMapError(null);
|
|
@@ -1169,7 +1284,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1169
1284
|
isMounted = false;
|
|
1170
1285
|
};
|
|
1171
1286
|
}, [client.maps, mapId, onError, onLoadingChange]);
|
|
1172
|
-
(0,
|
|
1287
|
+
(0, import_react4.useEffect)(() => {
|
|
1173
1288
|
if (normalizedLayers.length === 0) {
|
|
1174
1289
|
setLayers([]);
|
|
1175
1290
|
setBaseStates([]);
|
|
@@ -1200,7 +1315,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1200
1315
|
setMapOverrides(initialOverrides);
|
|
1201
1316
|
setUiOverrides([]);
|
|
1202
1317
|
}, [normalizedLayers]);
|
|
1203
|
-
(0,
|
|
1318
|
+
(0, import_react4.useEffect)(() => {
|
|
1204
1319
|
if (!layerControls) {
|
|
1205
1320
|
setControlOverrides([]);
|
|
1206
1321
|
return;
|
|
@@ -1212,7 +1327,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1212
1327
|
}));
|
|
1213
1328
|
setControlOverrides(overrides);
|
|
1214
1329
|
}, [layerControls]);
|
|
1215
|
-
(0,
|
|
1330
|
+
(0, import_react4.useEffect)(() => {
|
|
1216
1331
|
if (layerStates) {
|
|
1217
1332
|
return;
|
|
1218
1333
|
}
|
|
@@ -1222,12 +1337,12 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1222
1337
|
onLayerStateChange?.(reset);
|
|
1223
1338
|
}
|
|
1224
1339
|
}, [baseStates, effectiveStates.length, layerControls, layerStates, onLayerStateChange]);
|
|
1225
|
-
(0,
|
|
1340
|
+
(0, import_react4.useEffect)(() => {
|
|
1226
1341
|
if (layerStates) {
|
|
1227
1342
|
setEffectiveStates(layerStates);
|
|
1228
1343
|
}
|
|
1229
1344
|
}, [layerStates]);
|
|
1230
|
-
(0,
|
|
1345
|
+
(0, import_react4.useEffect)(() => {
|
|
1231
1346
|
if (layerStates) {
|
|
1232
1347
|
return;
|
|
1233
1348
|
}
|
|
@@ -1240,11 +1355,11 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1240
1355
|
setEffectiveStates(next);
|
|
1241
1356
|
onLayerStateChange?.(next);
|
|
1242
1357
|
}, [baseStates, controlOverrides, layerStates, mapOverrides, onLayerStateChange, uiOverrides]);
|
|
1243
|
-
(0,
|
|
1358
|
+
(0, import_react4.useEffect)(() => {
|
|
1244
1359
|
if (!Array.isArray(layerControls) || layerControls.length > 0) return;
|
|
1245
1360
|
setUiOverrides([]);
|
|
1246
1361
|
}, [layerControls]);
|
|
1247
|
-
(0,
|
|
1362
|
+
(0, import_react4.useEffect)(() => {
|
|
1248
1363
|
if (layerStates) {
|
|
1249
1364
|
return;
|
|
1250
1365
|
}
|
|
@@ -1264,18 +1379,13 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1264
1379
|
return [...filtered, nextEntry];
|
|
1265
1380
|
});
|
|
1266
1381
|
};
|
|
1267
|
-
const updateOpacityFromUi = (0,
|
|
1382
|
+
const updateOpacityFromUi = (0, import_react4.useCallback)(
|
|
1268
1383
|
(layerId, uiOpacity) => {
|
|
1269
1384
|
const meta = layerMetaIndex.get(String(layerId));
|
|
1270
|
-
const
|
|
1385
|
+
const baseOpacity = clampOpacity3(uiOpacity);
|
|
1386
|
+
const effectiveOpacity = calculateZoomBasedOpacity(
|
|
1271
1387
|
currentZoom,
|
|
1272
|
-
meta?.layerType,
|
|
1273
|
-
meta?.geometryType
|
|
1274
|
-
);
|
|
1275
|
-
const baseOpacity = clampOpacity3(uiOpacity / zoomFactor);
|
|
1276
|
-
const effectiveOpacity = getEffectiveLayerOpacity(
|
|
1277
1388
|
baseOpacity,
|
|
1278
|
-
currentZoom,
|
|
1279
1389
|
meta?.layerType,
|
|
1280
1390
|
meta?.geometryType
|
|
1281
1391
|
);
|
|
@@ -1308,7 +1418,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1308
1418
|
},
|
|
1309
1419
|
[currentZoom, effectiveStates, layerMetaIndex, layerStates, onLayerStateChange]
|
|
1310
1420
|
);
|
|
1311
|
-
const center = (0,
|
|
1421
|
+
const center = (0, import_react4.useMemo)(() => {
|
|
1312
1422
|
if (initialCenter) {
|
|
1313
1423
|
return initialCenter;
|
|
1314
1424
|
}
|
|
@@ -1319,36 +1429,30 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1319
1429
|
return DEFAULT_CENTER;
|
|
1320
1430
|
}, [initialCenter, map?.settings?.center]);
|
|
1321
1431
|
const zoom = initialZoom ?? map?.settings?.zoom ?? DEFAULT_ZOOM;
|
|
1322
|
-
(0,
|
|
1432
|
+
(0, import_react4.useEffect)(() => {
|
|
1323
1433
|
setCurrentZoom(zoom);
|
|
1324
1434
|
}, [zoom]);
|
|
1325
|
-
const decoratedLayers = (0,
|
|
1435
|
+
const decoratedLayers = (0, import_react4.useMemo)(() => {
|
|
1326
1436
|
return layers.map((layer) => ({
|
|
1327
1437
|
...layer,
|
|
1328
1438
|
effective: effectiveStates.find((state) => state.layerId === layer.mapLayer.layerId),
|
|
1329
1439
|
data: layerGeojson?.[layer.mapLayer.layerId] ?? layerGeojson?.[String(layer.mapLayer.layerId)] ?? null
|
|
1330
1440
|
}));
|
|
1331
1441
|
}, [effectiveStates, layerGeojson, layers]);
|
|
1332
|
-
const orderedLayers = (0,
|
|
1442
|
+
const orderedLayers = (0, import_react4.useMemo)(() => {
|
|
1333
1443
|
return [...decoratedLayers].filter((layer) => layer.effective?.visible && layer.data).sort((a, b) => a.displayOrder - b.displayOrder);
|
|
1334
1444
|
}, [decoratedLayers]);
|
|
1335
|
-
const
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
const autoZoomBBox = (0, import_react.useMemo)(() => {
|
|
1341
|
-
if (explicitZoomBBox) return null;
|
|
1342
|
-
const visibleBBoxes = orderedLayers.map((layer) => computeBBoxFromGeojson(layer.data));
|
|
1343
|
-
return mergeBBoxes(visibleBBoxes);
|
|
1344
|
-
}, [explicitZoomBBox, orderedLayers]);
|
|
1345
|
-
const resolveLayerStyle = (0, import_react.useCallback)(
|
|
1445
|
+
const autoZoomGeojson = (0, import_react4.useMemo)(
|
|
1446
|
+
() => orderedLayers.map((layer) => layer.data).filter((collection) => !!collection),
|
|
1447
|
+
[orderedLayers]
|
|
1448
|
+
);
|
|
1449
|
+
const resolveLayerStyle = (0, import_react4.useCallback)(
|
|
1346
1450
|
(layerId) => {
|
|
1347
1451
|
return getStyleByLayerId(layerId, mapLayers) ?? layerStyleIndex.get(String(layerId)) ?? null;
|
|
1348
1452
|
},
|
|
1349
1453
|
[layerStyleIndex, mapLayers]
|
|
1350
1454
|
);
|
|
1351
|
-
const labelMarkers = (0,
|
|
1455
|
+
const labelMarkers = (0, import_react4.useMemo)(() => {
|
|
1352
1456
|
const markers = [];
|
|
1353
1457
|
decoratedLayers.forEach((layerState) => {
|
|
1354
1458
|
if (!layerState.effective?.visible) return;
|
|
@@ -1358,7 +1462,14 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1358
1462
|
if (!data) return;
|
|
1359
1463
|
const resolvedStyle = resolveLayerStyle(layerState.mapLayer.layerId);
|
|
1360
1464
|
const layerColor = resolvedStyle?.fillColor ?? resolvedStyle?.color ?? "rgba(37, 99, 235, 1)";
|
|
1361
|
-
const
|
|
1465
|
+
const meta = layerMetaIndex.get(String(layerState.mapLayer.layerId));
|
|
1466
|
+
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
1467
|
+
const opacity = calculateZoomBasedOpacity(
|
|
1468
|
+
currentZoom,
|
|
1469
|
+
baseOpacity,
|
|
1470
|
+
meta?.layerType,
|
|
1471
|
+
meta?.geometryType
|
|
1472
|
+
);
|
|
1362
1473
|
data.features.forEach((feature, index) => {
|
|
1363
1474
|
const properties = feature.properties;
|
|
1364
1475
|
const value = properties?.[labelKey];
|
|
@@ -1377,8 +1488,8 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1377
1488
|
});
|
|
1378
1489
|
});
|
|
1379
1490
|
return markers;
|
|
1380
|
-
}, [decoratedLayers, labelKeyIndex, resolveLayerStyle]);
|
|
1381
|
-
const ensureLayerPanes = (0,
|
|
1491
|
+
}, [currentZoom, decoratedLayers, labelKeyIndex, layerMetaIndex, resolveLayerStyle]);
|
|
1492
|
+
const ensureLayerPanes = (0, import_react4.useCallback)(
|
|
1382
1493
|
(targetMap, targetLayers) => {
|
|
1383
1494
|
const baseZIndex = 400;
|
|
1384
1495
|
targetLayers.forEach((layer) => {
|
|
@@ -1394,7 +1505,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1394
1505
|
},
|
|
1395
1506
|
[]
|
|
1396
1507
|
);
|
|
1397
|
-
const handleMapReady = (0,
|
|
1508
|
+
const handleMapReady = (0, import_react4.useCallback)(
|
|
1398
1509
|
(instance) => {
|
|
1399
1510
|
setPanesReady(false);
|
|
1400
1511
|
setMapInstance(instance);
|
|
@@ -1402,7 +1513,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1402
1513
|
},
|
|
1403
1514
|
[onMapReady]
|
|
1404
1515
|
);
|
|
1405
|
-
(0,
|
|
1516
|
+
(0, import_react4.useEffect)(() => {
|
|
1406
1517
|
if (!mapInstance) {
|
|
1407
1518
|
setPanesReady(false);
|
|
1408
1519
|
return;
|
|
@@ -1422,19 +1533,19 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1422
1533
|
setPanesReady(true);
|
|
1423
1534
|
}
|
|
1424
1535
|
}, [mapInstance, orderedLayers, ensureLayerPanes]);
|
|
1425
|
-
const overlayOnEachFeature = (0,
|
|
1536
|
+
const overlayOnEachFeature = (0, import_react4.useMemo)(() => {
|
|
1426
1537
|
return (feature, layer) => {
|
|
1427
1538
|
const layerId = getFeatureLayerId(feature) ?? void 0;
|
|
1428
1539
|
const geometryType = feature?.geometry?.type;
|
|
1429
|
-
const isPointFeature = geometryType === "Point" || geometryType === "MultiPoint" || layer instanceof
|
|
1430
|
-
const originalStyle = layer instanceof
|
|
1540
|
+
const isPointFeature = geometryType === "Point" || geometryType === "MultiPoint" || layer instanceof import_leaflet4.default.CircleMarker;
|
|
1541
|
+
const originalStyle = layer instanceof import_leaflet4.default.Path ? {
|
|
1431
1542
|
color: layer.options.color,
|
|
1432
1543
|
weight: layer.options.weight,
|
|
1433
1544
|
fillColor: layer.options.fillColor,
|
|
1434
1545
|
opacity: layer.options.opacity,
|
|
1435
1546
|
fillOpacity: layer.options.fillOpacity
|
|
1436
1547
|
} : null;
|
|
1437
|
-
const originalRadius = layer instanceof
|
|
1548
|
+
const originalRadius = layer instanceof import_leaflet4.default.CircleMarker ? layer.getRadius() : null;
|
|
1438
1549
|
if (featureInfoMode === "popup") {
|
|
1439
1550
|
const content = buildFeaturePopupHtml(feature);
|
|
1440
1551
|
if (content) {
|
|
@@ -1443,11 +1554,10 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1443
1554
|
maxWidth,
|
|
1444
1555
|
minWidth,
|
|
1445
1556
|
maxHeight,
|
|
1446
|
-
className: "
|
|
1557
|
+
className: "custom-leaflet-popup",
|
|
1447
1558
|
autoPan: true,
|
|
1448
1559
|
closeButton: true,
|
|
1449
|
-
keepInView: true
|
|
1450
|
-
offset: import_leaflet.default.point(0, -24)
|
|
1560
|
+
keepInView: true
|
|
1451
1561
|
});
|
|
1452
1562
|
}
|
|
1453
1563
|
}
|
|
@@ -1492,7 +1602,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1492
1602
|
onFeatureClick?.(feature, layerId);
|
|
1493
1603
|
});
|
|
1494
1604
|
layer.on("mouseover", () => {
|
|
1495
|
-
if (layer instanceof
|
|
1605
|
+
if (layer instanceof import_leaflet4.default.Path && originalStyle) {
|
|
1496
1606
|
layer.setStyle({
|
|
1497
1607
|
...originalStyle,
|
|
1498
1608
|
weight: (originalStyle.weight ?? 2) + 1,
|
|
@@ -1500,16 +1610,16 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1500
1610
|
fillOpacity: Math.min(1, (originalStyle.fillOpacity ?? 0.8) + 0.1)
|
|
1501
1611
|
});
|
|
1502
1612
|
}
|
|
1503
|
-
if (layer instanceof
|
|
1613
|
+
if (layer instanceof import_leaflet4.default.CircleMarker && typeof originalRadius === "number") {
|
|
1504
1614
|
layer.setRadius(originalRadius + 1);
|
|
1505
1615
|
}
|
|
1506
1616
|
onFeatureHover?.(feature, layerId);
|
|
1507
1617
|
});
|
|
1508
1618
|
layer.on("mouseout", () => {
|
|
1509
|
-
if (layer instanceof
|
|
1619
|
+
if (layer instanceof import_leaflet4.default.Path && originalStyle) {
|
|
1510
1620
|
layer.setStyle(originalStyle);
|
|
1511
1621
|
}
|
|
1512
|
-
if (layer instanceof
|
|
1622
|
+
if (layer instanceof import_leaflet4.default.CircleMarker && typeof originalRadius === "number") {
|
|
1513
1623
|
layer.setRadius(originalRadius);
|
|
1514
1624
|
}
|
|
1515
1625
|
});
|
|
@@ -1521,80 +1631,20 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1521
1631
|
const resolvedStyle = featureStyleOverrides ? { ...style ?? {}, ...featureStyleOverrides } : style;
|
|
1522
1632
|
const geometryType = feature?.geometry?.type;
|
|
1523
1633
|
const resolvedLayerType = layerType ?? geometryType;
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
resolvedLayerType
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
color: resolvedStyle?.color ?? resolvedStyle?.fillColor ?? "#2563eb",
|
|
1536
|
-
weight: resolvedStyle?.weight ?? 2,
|
|
1537
|
-
fillColor: resolvedStyle?.fillColor ?? resolvedStyle?.color ?? "#2563eb",
|
|
1538
|
-
opacity: strokeOpacity,
|
|
1539
|
-
fillOpacity
|
|
1634
|
+
return layerStyleToLeaflet({
|
|
1635
|
+
baseOpacity,
|
|
1636
|
+
zoom: currentZoom,
|
|
1637
|
+
layerStyle: resolvedStyle,
|
|
1638
|
+
geometryType,
|
|
1639
|
+
layerType: resolvedLayerType
|
|
1640
|
+
});
|
|
1641
|
+
};
|
|
1642
|
+
const makeStyleFnForLayer = (layerId) => {
|
|
1643
|
+
return (feature, layerType, baseOpacity) => {
|
|
1644
|
+
return buildLayerStyle(layerId, baseOpacity ?? 1, feature, layerType);
|
|
1540
1645
|
};
|
|
1541
1646
|
};
|
|
1542
|
-
|
|
1543
|
-
const size = 60;
|
|
1544
|
-
const innerSize = 44;
|
|
1545
|
-
const textStyles = getLabelTextStyles(color);
|
|
1546
|
-
const safeLabel = escapeHtml(label);
|
|
1547
|
-
const clampedOpacity = Math.min(1, Math.max(0.92, opacity));
|
|
1548
|
-
const innerBackground = withAlpha(color, 0.9);
|
|
1549
|
-
return import_leaflet.default.divIcon({
|
|
1550
|
-
className: "zenit-label-marker",
|
|
1551
|
-
iconSize: [size, size],
|
|
1552
|
-
iconAnchor: [size / 2, size / 2],
|
|
1553
|
-
html: `
|
|
1554
|
-
<div
|
|
1555
|
-
title="${safeLabel}"
|
|
1556
|
-
style="
|
|
1557
|
-
width:${size}px;
|
|
1558
|
-
height:${size}px;
|
|
1559
|
-
border-radius:9999px;
|
|
1560
|
-
background:rgba(255, 255, 255, 0.95);
|
|
1561
|
-
border:3px solid rgba(255, 255, 255, 1);
|
|
1562
|
-
display:flex;
|
|
1563
|
-
align-items:center;
|
|
1564
|
-
justify-content:center;
|
|
1565
|
-
opacity:${clampedOpacity};
|
|
1566
|
-
box-shadow:0 2px 6px rgba(0, 0, 0, 0.25);
|
|
1567
|
-
pointer-events:none;
|
|
1568
|
-
"
|
|
1569
|
-
>
|
|
1570
|
-
<div
|
|
1571
|
-
style="
|
|
1572
|
-
width:${innerSize}px;
|
|
1573
|
-
height:${innerSize}px;
|
|
1574
|
-
border-radius:9999px;
|
|
1575
|
-
background:${innerBackground};
|
|
1576
|
-
display:flex;
|
|
1577
|
-
align-items:center;
|
|
1578
|
-
justify-content:center;
|
|
1579
|
-
box-shadow:inset 0 0 0 1px rgba(15, 23, 42, 0.12);
|
|
1580
|
-
"
|
|
1581
|
-
>
|
|
1582
|
-
<span
|
|
1583
|
-
style="
|
|
1584
|
-
color:${textStyles.color};
|
|
1585
|
-
font-size:20px;
|
|
1586
|
-
font-weight:800;
|
|
1587
|
-
text-shadow:${textStyles.shadow};
|
|
1588
|
-
"
|
|
1589
|
-
>
|
|
1590
|
-
${safeLabel}
|
|
1591
|
-
</span>
|
|
1592
|
-
</div>
|
|
1593
|
-
</div>
|
|
1594
|
-
`
|
|
1595
|
-
});
|
|
1596
|
-
}, []);
|
|
1597
|
-
(0, import_react.useImperativeHandle)(ref, () => ({
|
|
1647
|
+
(0, import_react4.useImperativeHandle)(ref, () => ({
|
|
1598
1648
|
setLayerOpacity: (layerId, opacity) => {
|
|
1599
1649
|
upsertUiOverride(layerId, { overrideOpacity: opacity });
|
|
1600
1650
|
},
|
|
@@ -1644,10 +1694,10 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1644
1694
|
getMapInstance: () => mapInstance
|
|
1645
1695
|
}), [effectiveStates, mapInstance]);
|
|
1646
1696
|
if (loadingMap) {
|
|
1647
|
-
return /* @__PURE__ */ (0,
|
|
1697
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { padding: 16, height, width }, children: "Cargando mapa..." });
|
|
1648
1698
|
}
|
|
1649
1699
|
if (mapError) {
|
|
1650
|
-
return /* @__PURE__ */ (0,
|
|
1700
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { padding: 16, height, width, color: "red" }, children: [
|
|
1651
1701
|
"Error al cargar mapa: ",
|
|
1652
1702
|
mapError
|
|
1653
1703
|
] });
|
|
@@ -1659,7 +1709,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1659
1709
|
setCurrentZoom(zoomValue);
|
|
1660
1710
|
onZoomChange?.(zoomValue);
|
|
1661
1711
|
};
|
|
1662
|
-
return /* @__PURE__ */ (0,
|
|
1712
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1663
1713
|
"div",
|
|
1664
1714
|
{
|
|
1665
1715
|
style: {
|
|
@@ -1672,13 +1722,13 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1672
1722
|
boxSizing: "border-box"
|
|
1673
1723
|
},
|
|
1674
1724
|
children: [
|
|
1675
|
-
/* @__PURE__ */ (0,
|
|
1725
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1676
1726
|
"div",
|
|
1677
1727
|
{
|
|
1678
1728
|
className: `zenit-map-shell${isPopupOpen ? " popup-open" : ""}`,
|
|
1679
1729
|
style: { flex: 1, position: "relative" },
|
|
1680
|
-
children: /* @__PURE__ */ (0,
|
|
1681
|
-
|
|
1730
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1731
|
+
import_react_leaflet4.MapContainer,
|
|
1682
1732
|
{
|
|
1683
1733
|
center,
|
|
1684
1734
|
zoom,
|
|
@@ -1686,57 +1736,68 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1686
1736
|
scrollWheelZoom: true,
|
|
1687
1737
|
zoomControl: false,
|
|
1688
1738
|
children: [
|
|
1689
|
-
/* @__PURE__ */ (0,
|
|
1690
|
-
|
|
1739
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1740
|
+
import_react_leaflet4.TileLayer,
|
|
1691
1741
|
{
|
|
1692
1742
|
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
1693
1743
|
attribution: "\xA9 OpenStreetMap contributors"
|
|
1694
1744
|
}
|
|
1695
1745
|
),
|
|
1696
|
-
/* @__PURE__ */ (0,
|
|
1697
|
-
/* @__PURE__ */ (0,
|
|
1698
|
-
/* @__PURE__ */ (0,
|
|
1699
|
-
|
|
1700
|
-
|
|
1746
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_leaflet4.ZoomControl, { position: "topright" }),
|
|
1747
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MapInstanceBridge, { onReady: handleMapReady }),
|
|
1748
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1749
|
+
BBoxZoomHandler,
|
|
1750
|
+
{
|
|
1751
|
+
bbox: zoomToBbox ?? void 0,
|
|
1752
|
+
geojson: zoomToGeojson ?? void 0,
|
|
1753
|
+
autoGeojson: autoZoomGeojson
|
|
1754
|
+
}
|
|
1755
|
+
),
|
|
1756
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ZoomBasedOpacityHandler, { onZoomChange: handleZoomChange }),
|
|
1757
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LocationControl, {}),
|
|
1701
1758
|
orderedLayers.map((layerState) => {
|
|
1702
1759
|
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
1703
1760
|
const fillPaneName = `zenit-layer-${layerState.mapLayer.layerId}-fill`;
|
|
1704
1761
|
const pointsPaneName = `zenit-layer-${layerState.mapLayer.layerId}-points`;
|
|
1705
1762
|
const layerType = layerState.layer?.layerType ?? layerState.mapLayer.layerType ?? void 0;
|
|
1706
|
-
const
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
1711
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.default.Fragment, { children: [
|
|
1712
|
-
fillData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1713
|
-
import_react_leaflet.GeoJSON,
|
|
1714
|
-
{
|
|
1715
|
-
data: fillData,
|
|
1716
|
-
pane: panesReady && mapInstance?.getPane(fillPaneName) ? fillPaneName : void 0,
|
|
1717
|
-
style: (feature) => buildLayerStyle(layerState.mapLayer.layerId, baseOpacity, feature, layerType),
|
|
1718
|
-
onEachFeature: overlayOnEachFeature
|
|
1719
|
-
}
|
|
1720
|
-
),
|
|
1721
|
-
pointsData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1722
|
-
import_react_leaflet.GeoJSON,
|
|
1763
|
+
const labelKey = labelKeyIndex.get(String(layerState.mapLayer.layerId));
|
|
1764
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.default.Fragment, { children: [
|
|
1765
|
+
layerState.data && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1766
|
+
LayerGeoJson,
|
|
1723
1767
|
{
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1768
|
+
layerId: layerState.mapLayer.layerId,
|
|
1769
|
+
data: layerState.data,
|
|
1770
|
+
baseOpacity,
|
|
1771
|
+
isMobile,
|
|
1772
|
+
panesReady,
|
|
1773
|
+
mapInstance,
|
|
1774
|
+
fillPaneName,
|
|
1775
|
+
pointsPaneName,
|
|
1776
|
+
layerType,
|
|
1777
|
+
styleFn: makeStyleFnForLayer(layerState.mapLayer.layerId),
|
|
1778
|
+
onEachFeature: overlayOnEachFeature,
|
|
1779
|
+
onPolygonLabel: labelKey ? (feature, layer) => {
|
|
1780
|
+
const geometryType = feature?.geometry?.type;
|
|
1781
|
+
if (geometryType !== "Polygon" && geometryType !== "MultiPolygon") return;
|
|
1782
|
+
const properties = feature?.properties;
|
|
1783
|
+
const value = properties?.[labelKey];
|
|
1784
|
+
if (!value || !layer.bindTooltip) return;
|
|
1785
|
+
layer.bindTooltip(String(value), {
|
|
1786
|
+
sticky: true,
|
|
1787
|
+
direction: "center",
|
|
1788
|
+
opacity: 0.9,
|
|
1789
|
+
className: "polygon-label-tooltip"
|
|
1790
|
+
});
|
|
1791
|
+
} : void 0
|
|
1731
1792
|
}
|
|
1732
1793
|
),
|
|
1733
1794
|
panesReady && mapInstance?.getPane(LABELS_PANE_NAME) ? labelMarkers.filter(
|
|
1734
1795
|
(marker) => String(marker.layerId) === String(layerState.mapLayer.layerId)
|
|
1735
|
-
).map((marker) => /* @__PURE__ */ (0,
|
|
1736
|
-
|
|
1796
|
+
).map((marker) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1797
|
+
import_react_leaflet4.Marker,
|
|
1737
1798
|
{
|
|
1738
1799
|
position: marker.position,
|
|
1739
|
-
icon:
|
|
1800
|
+
icon: createCustomIcon(marker.label, marker.opacity, marker.color),
|
|
1740
1801
|
interactive: false,
|
|
1741
1802
|
pane: LABELS_PANE_NAME
|
|
1742
1803
|
},
|
|
@@ -1744,14 +1805,20 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1744
1805
|
)) : null
|
|
1745
1806
|
] }, layerState.mapLayer.layerId.toString());
|
|
1746
1807
|
}),
|
|
1747
|
-
overlayGeojson && /* @__PURE__ */ (0,
|
|
1748
|
-
|
|
1808
|
+
overlayGeojson && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1809
|
+
LayerGeoJson,
|
|
1749
1810
|
{
|
|
1811
|
+
layerId: "overlay-geojson",
|
|
1750
1812
|
data: overlayGeojson,
|
|
1751
|
-
|
|
1813
|
+
baseOpacity: 1,
|
|
1814
|
+
isMobile,
|
|
1815
|
+
panesReady,
|
|
1816
|
+
mapInstance,
|
|
1817
|
+
fillPaneName: "zenit-overlay-fill",
|
|
1818
|
+
pointsPaneName: "zenit-overlay-points",
|
|
1819
|
+
styleFn: overlayStyleFn,
|
|
1752
1820
|
onEachFeature: overlayOnEachFeature
|
|
1753
|
-
}
|
|
1754
|
-
"zenit-overlay-geojson"
|
|
1821
|
+
}
|
|
1755
1822
|
)
|
|
1756
1823
|
]
|
|
1757
1824
|
},
|
|
@@ -1759,7 +1826,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1759
1826
|
)
|
|
1760
1827
|
}
|
|
1761
1828
|
),
|
|
1762
|
-
showLayerPanel && decoratedLayers.length > 0 && /* @__PURE__ */ (0,
|
|
1829
|
+
showLayerPanel && decoratedLayers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1763
1830
|
"div",
|
|
1764
1831
|
{
|
|
1765
1832
|
style: {
|
|
@@ -1772,7 +1839,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1772
1839
|
overflowY: "auto"
|
|
1773
1840
|
},
|
|
1774
1841
|
children: [
|
|
1775
|
-
overlayGeojson && /* @__PURE__ */ (0,
|
|
1842
|
+
overlayGeojson && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1776
1843
|
"div",
|
|
1777
1844
|
{
|
|
1778
1845
|
style: {
|
|
@@ -1784,8 +1851,8 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1784
1851
|
marginBottom: 12
|
|
1785
1852
|
},
|
|
1786
1853
|
children: [
|
|
1787
|
-
/* @__PURE__ */ (0,
|
|
1788
|
-
/* @__PURE__ */ (0,
|
|
1854
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontWeight: 600, marginBottom: 4 }, children: "Overlay activo" }),
|
|
1855
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { fontSize: 13 }, children: [
|
|
1789
1856
|
"GeoJSON externo con ",
|
|
1790
1857
|
(overlayGeojson.features?.length ?? 0).toLocaleString(),
|
|
1791
1858
|
" elementos."
|
|
@@ -1793,14 +1860,14 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1793
1860
|
]
|
|
1794
1861
|
}
|
|
1795
1862
|
),
|
|
1796
|
-
/* @__PURE__ */ (0,
|
|
1797
|
-
decoratedLayers.map((layerState) => /* @__PURE__ */ (0,
|
|
1863
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontWeight: 600, marginBottom: 12 }, children: "Capas" }),
|
|
1864
|
+
decoratedLayers.map((layerState) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1798
1865
|
"div",
|
|
1799
1866
|
{
|
|
1800
1867
|
style: { borderBottom: "1px solid #e5e7eb", paddingBottom: 10, marginBottom: 10 },
|
|
1801
1868
|
children: [
|
|
1802
|
-
/* @__PURE__ */ (0,
|
|
1803
|
-
/* @__PURE__ */ (0,
|
|
1869
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
|
1870
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1804
1871
|
"input",
|
|
1805
1872
|
{
|
|
1806
1873
|
type: "checkbox",
|
|
@@ -1811,17 +1878,17 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1811
1878
|
}
|
|
1812
1879
|
}
|
|
1813
1880
|
),
|
|
1814
|
-
/* @__PURE__ */ (0,
|
|
1881
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: layerState.layer?.name ?? `Capa ${layerState.mapLayer.layerId}` })
|
|
1815
1882
|
] }),
|
|
1816
|
-
/* @__PURE__ */ (0,
|
|
1817
|
-
/* @__PURE__ */ (0,
|
|
1818
|
-
/* @__PURE__ */ (0,
|
|
1819
|
-
/* @__PURE__ */ (0,
|
|
1883
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { marginTop: 8 }, children: [
|
|
1884
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 4 }, children: [
|
|
1885
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "#4a5568" }, children: "Opacidad" }),
|
|
1886
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
|
|
1820
1887
|
Math.round((layerState.effective?.opacity ?? 1) * 100),
|
|
1821
1888
|
"%"
|
|
1822
1889
|
] })
|
|
1823
1890
|
] }),
|
|
1824
|
-
/* @__PURE__ */ (0,
|
|
1891
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1825
1892
|
"input",
|
|
1826
1893
|
{
|
|
1827
1894
|
type: "range",
|
|
@@ -1851,13 +1918,13 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1851
1918
|
ZenitMap.displayName = "ZenitMap";
|
|
1852
1919
|
|
|
1853
1920
|
// src/react/ZenitLayerManager.tsx
|
|
1854
|
-
var
|
|
1921
|
+
var import_react5 = __toESM(require("react"));
|
|
1855
1922
|
|
|
1856
1923
|
// src/react/icons.tsx
|
|
1857
1924
|
var import_lucide_react = require("lucide-react");
|
|
1858
1925
|
|
|
1859
1926
|
// src/react/ZenitLayerManager.tsx
|
|
1860
|
-
var
|
|
1927
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1861
1928
|
var FLOAT_TOLERANCE = 1e-3;
|
|
1862
1929
|
function areEffectiveStatesEqual(a, b) {
|
|
1863
1930
|
if (a.length !== b.length) return false;
|
|
@@ -1897,15 +1964,15 @@ var ZenitLayerManager = ({
|
|
|
1897
1964
|
layerFeatureCounts,
|
|
1898
1965
|
mapLayers
|
|
1899
1966
|
}) => {
|
|
1900
|
-
const [map, setMap] = (0,
|
|
1901
|
-
const [loadingMap, setLoadingMap] = (0,
|
|
1902
|
-
const [mapError, setMapError] = (0,
|
|
1903
|
-
const [layers, setLayers] = (0,
|
|
1904
|
-
const [activeTab, setActiveTab] = (0,
|
|
1905
|
-
const [panelVisible, setPanelVisible] = (0,
|
|
1906
|
-
const lastEmittedStatesRef = (0,
|
|
1967
|
+
const [map, setMap] = (0, import_react5.useState)(null);
|
|
1968
|
+
const [loadingMap, setLoadingMap] = (0, import_react5.useState)(false);
|
|
1969
|
+
const [mapError, setMapError] = (0, import_react5.useState)(null);
|
|
1970
|
+
const [layers, setLayers] = (0, import_react5.useState)([]);
|
|
1971
|
+
const [activeTab, setActiveTab] = (0, import_react5.useState)("layers");
|
|
1972
|
+
const [panelVisible, setPanelVisible] = (0, import_react5.useState)(true);
|
|
1973
|
+
const lastEmittedStatesRef = (0, import_react5.useRef)(null);
|
|
1907
1974
|
const isControlled = Array.isArray(layerStates) && typeof onLayerStatesChange === "function";
|
|
1908
|
-
const baseStates = (0,
|
|
1975
|
+
const baseStates = (0, import_react5.useMemo)(
|
|
1909
1976
|
() => initLayerStates(
|
|
1910
1977
|
layers.map((entry) => ({
|
|
1911
1978
|
...entry.mapLayer,
|
|
@@ -1916,7 +1983,7 @@ var ZenitLayerManager = ({
|
|
|
1916
1983
|
),
|
|
1917
1984
|
[layers]
|
|
1918
1985
|
);
|
|
1919
|
-
const overrideStates = (0,
|
|
1986
|
+
const overrideStates = (0, import_react5.useMemo)(
|
|
1920
1987
|
() => layers.map(
|
|
1921
1988
|
(entry) => ({
|
|
1922
1989
|
layerId: entry.mapLayer.layerId,
|
|
@@ -1926,11 +1993,11 @@ var ZenitLayerManager = ({
|
|
|
1926
1993
|
),
|
|
1927
1994
|
[layers]
|
|
1928
1995
|
);
|
|
1929
|
-
const effectiveStates = (0,
|
|
1996
|
+
const effectiveStates = (0, import_react5.useMemo)(
|
|
1930
1997
|
() => layerStates ?? applyLayerOverrides(baseStates, overrideStates),
|
|
1931
1998
|
[baseStates, layerStates, overrideStates]
|
|
1932
1999
|
);
|
|
1933
|
-
const layerMetaIndex = (0,
|
|
2000
|
+
const layerMetaIndex = (0, import_react5.useMemo)(() => {
|
|
1934
2001
|
const index = /* @__PURE__ */ new Map();
|
|
1935
2002
|
mapLayers?.forEach((entry) => {
|
|
1936
2003
|
const key = String(entry.layerId);
|
|
@@ -1944,7 +2011,7 @@ var ZenitLayerManager = ({
|
|
|
1944
2011
|
});
|
|
1945
2012
|
return index;
|
|
1946
2013
|
}, [map, mapLayers]);
|
|
1947
|
-
const resolveUserOpacity =
|
|
2014
|
+
const resolveUserOpacity = import_react5.default.useCallback((state) => {
|
|
1948
2015
|
if (typeof state.overrideOpacity === "number") return state.overrideOpacity;
|
|
1949
2016
|
if (typeof state.overrideOpacity === "string") {
|
|
1950
2017
|
const parsed = Number.parseFloat(state.overrideOpacity);
|
|
@@ -1952,7 +2019,7 @@ var ZenitLayerManager = ({
|
|
|
1952
2019
|
}
|
|
1953
2020
|
return state.opacity ?? 1;
|
|
1954
2021
|
}, []);
|
|
1955
|
-
const resolveEffectiveOpacity =
|
|
2022
|
+
const resolveEffectiveOpacity = import_react5.default.useCallback(
|
|
1956
2023
|
(layerId, userOpacity) => {
|
|
1957
2024
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
1958
2025
|
return userOpacity;
|
|
@@ -1968,7 +2035,7 @@ var ZenitLayerManager = ({
|
|
|
1968
2035
|
},
|
|
1969
2036
|
[autoOpacityConfig, autoOpacityOnZoom, layerMetaIndex, mapZoom]
|
|
1970
2037
|
);
|
|
1971
|
-
const effectiveStatesWithZoom = (0,
|
|
2038
|
+
const effectiveStatesWithZoom = (0, import_react5.useMemo)(() => {
|
|
1972
2039
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
1973
2040
|
return effectiveStates;
|
|
1974
2041
|
}
|
|
@@ -1982,7 +2049,7 @@ var ZenitLayerManager = ({
|
|
|
1982
2049
|
};
|
|
1983
2050
|
});
|
|
1984
2051
|
}, [autoOpacityOnZoom, effectiveStates, mapZoom, resolveEffectiveOpacity, resolveUserOpacity]);
|
|
1985
|
-
(0,
|
|
2052
|
+
(0, import_react5.useEffect)(() => {
|
|
1986
2053
|
let cancelled = false;
|
|
1987
2054
|
setLoadingMap(true);
|
|
1988
2055
|
setMapError(null);
|
|
@@ -2014,12 +2081,12 @@ var ZenitLayerManager = ({
|
|
|
2014
2081
|
cancelled = true;
|
|
2015
2082
|
};
|
|
2016
2083
|
}, [client.maps, mapId]);
|
|
2017
|
-
(0,
|
|
2084
|
+
(0, import_react5.useEffect)(() => {
|
|
2018
2085
|
if (!showUploadTab && activeTab === "upload") {
|
|
2019
2086
|
setActiveTab("layers");
|
|
2020
2087
|
}
|
|
2021
2088
|
}, [activeTab, showUploadTab]);
|
|
2022
|
-
(0,
|
|
2089
|
+
(0, import_react5.useEffect)(() => {
|
|
2023
2090
|
if (isControlled) return;
|
|
2024
2091
|
if (!onLayerStatesChange) return;
|
|
2025
2092
|
const emitStates = autoOpacityOnZoom && typeof mapZoom === "number" ? effectiveStatesWithZoom : effectiveStates;
|
|
@@ -2037,7 +2104,7 @@ var ZenitLayerManager = ({
|
|
|
2037
2104
|
mapZoom,
|
|
2038
2105
|
onLayerStatesChange
|
|
2039
2106
|
]);
|
|
2040
|
-
const updateLayerVisible =
|
|
2107
|
+
const updateLayerVisible = import_react5.default.useCallback(
|
|
2041
2108
|
(layerId, visible) => {
|
|
2042
2109
|
if (!onLayerStatesChange) return;
|
|
2043
2110
|
const next = effectiveStates.map(
|
|
@@ -2047,7 +2114,7 @@ var ZenitLayerManager = ({
|
|
|
2047
2114
|
},
|
|
2048
2115
|
[effectiveStates, onLayerStatesChange]
|
|
2049
2116
|
);
|
|
2050
|
-
const updateLayerOpacity =
|
|
2117
|
+
const updateLayerOpacity = import_react5.default.useCallback(
|
|
2051
2118
|
(layerId, opacity) => {
|
|
2052
2119
|
if (!onLayerStatesChange) return;
|
|
2053
2120
|
const adjustedOpacity = resolveEffectiveOpacity(layerId, opacity);
|
|
@@ -2058,7 +2125,7 @@ var ZenitLayerManager = ({
|
|
|
2058
2125
|
},
|
|
2059
2126
|
[effectiveStates, onLayerStatesChange, resolveEffectiveOpacity]
|
|
2060
2127
|
);
|
|
2061
|
-
const resolveFeatureCount =
|
|
2128
|
+
const resolveFeatureCount = import_react5.default.useCallback(
|
|
2062
2129
|
(layerId, layer) => {
|
|
2063
2130
|
const resolvedFeatureCount = layerFeatureCounts?.[layerId] ?? layerFeatureCounts?.[String(layerId)];
|
|
2064
2131
|
if (typeof resolvedFeatureCount === "number") return resolvedFeatureCount;
|
|
@@ -2067,7 +2134,7 @@ var ZenitLayerManager = ({
|
|
|
2067
2134
|
},
|
|
2068
2135
|
[layerFeatureCounts]
|
|
2069
2136
|
);
|
|
2070
|
-
const decoratedLayers = (0,
|
|
2137
|
+
const decoratedLayers = (0, import_react5.useMemo)(() => {
|
|
2071
2138
|
return layers.map((entry) => ({
|
|
2072
2139
|
...entry,
|
|
2073
2140
|
effective: effectiveStates.find((state) => state.layerId === entry.mapLayer.layerId),
|
|
@@ -2096,7 +2163,7 @@ var ZenitLayerManager = ({
|
|
|
2096
2163
|
return String(a.mapLayer.layerId).localeCompare(String(b.mapLayer.layerId));
|
|
2097
2164
|
});
|
|
2098
2165
|
}, [effectiveStates, layers, resolveFeatureCount]);
|
|
2099
|
-
const resolveLayerStyle =
|
|
2166
|
+
const resolveLayerStyle = import_react5.default.useCallback(
|
|
2100
2167
|
(layerId) => {
|
|
2101
2168
|
const layerKey = String(layerId);
|
|
2102
2169
|
const fromProp = mapLayers?.find((entry) => String(entry.layerId) === layerKey)?.style;
|
|
@@ -2126,10 +2193,10 @@ var ZenitLayerManager = ({
|
|
|
2126
2193
|
...height ? { height } : {}
|
|
2127
2194
|
};
|
|
2128
2195
|
if (loadingMap) {
|
|
2129
|
-
return /* @__PURE__ */ (0,
|
|
2196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: panelStyle, children: "Cargando capas\u2026" });
|
|
2130
2197
|
}
|
|
2131
2198
|
if (mapError) {
|
|
2132
|
-
return /* @__PURE__ */ (0,
|
|
2199
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className, style: { ...panelStyle, color: "#c53030" }, children: [
|
|
2133
2200
|
"Error al cargar mapa: ",
|
|
2134
2201
|
mapError
|
|
2135
2202
|
] });
|
|
@@ -2147,7 +2214,7 @@ var ZenitLayerManager = ({
|
|
|
2147
2214
|
boxShadow: "0 1px 0 rgba(148, 163, 184, 0.25)"
|
|
2148
2215
|
};
|
|
2149
2216
|
const renderLayerCards = () => {
|
|
2150
|
-
return /* @__PURE__ */ (0,
|
|
2217
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: decoratedLayers.map((layerState) => {
|
|
2151
2218
|
const layerId = layerState.mapLayer.layerId;
|
|
2152
2219
|
const layerName = layerState.layerName ?? `Capa ${layerId}`;
|
|
2153
2220
|
const visible = layerState.effective?.visible ?? false;
|
|
@@ -2157,7 +2224,7 @@ var ZenitLayerManager = ({
|
|
|
2157
2224
|
const muted = !visible;
|
|
2158
2225
|
const opacityPercent = Math.round(userOpacity * 100);
|
|
2159
2226
|
const sliderBackground = `linear-gradient(to right, ${layerColor} 0%, ${layerColor} ${opacityPercent}%, #e5e7eb ${opacityPercent}%, #e5e7eb 100%)`;
|
|
2160
|
-
return /* @__PURE__ */ (0,
|
|
2227
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2161
2228
|
"div",
|
|
2162
2229
|
{
|
|
2163
2230
|
className: `zlm-card${muted ? " is-muted" : ""}`,
|
|
@@ -2172,9 +2239,9 @@ var ZenitLayerManager = ({
|
|
|
2172
2239
|
width: "100%"
|
|
2173
2240
|
},
|
|
2174
2241
|
children: [
|
|
2175
|
-
/* @__PURE__ */ (0,
|
|
2176
|
-
/* @__PURE__ */ (0,
|
|
2177
|
-
/* @__PURE__ */ (0,
|
|
2242
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
|
|
2243
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: 10, alignItems: "flex-start", minWidth: 0, flex: 1 }, children: [
|
|
2244
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2178
2245
|
"div",
|
|
2179
2246
|
{
|
|
2180
2247
|
style: {
|
|
@@ -2189,7 +2256,7 @@ var ZenitLayerManager = ({
|
|
|
2189
2256
|
title: "Color de la capa"
|
|
2190
2257
|
}
|
|
2191
2258
|
),
|
|
2192
|
-
showLayerVisibilityIcon && /* @__PURE__ */ (0,
|
|
2259
|
+
showLayerVisibilityIcon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2193
2260
|
"button",
|
|
2194
2261
|
{
|
|
2195
2262
|
type: "button",
|
|
@@ -2200,11 +2267,11 @@ var ZenitLayerManager = ({
|
|
|
2200
2267
|
)
|
|
2201
2268
|
),
|
|
2202
2269
|
"aria-label": visible ? "Ocultar capa" : "Mostrar capa",
|
|
2203
|
-
children: visible ? /* @__PURE__ */ (0,
|
|
2270
|
+
children: visible ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Eye, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.EyeOff, { size: 16 })
|
|
2204
2271
|
}
|
|
2205
2272
|
),
|
|
2206
|
-
/* @__PURE__ */ (0,
|
|
2207
|
-
/* @__PURE__ */ (0,
|
|
2273
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { minWidth: 0, flex: 1 }, children: [
|
|
2274
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2208
2275
|
"div",
|
|
2209
2276
|
{
|
|
2210
2277
|
className: "zlm-layer-name",
|
|
@@ -2222,26 +2289,26 @@ var ZenitLayerManager = ({
|
|
|
2222
2289
|
children: layerName
|
|
2223
2290
|
}
|
|
2224
2291
|
),
|
|
2225
|
-
/* @__PURE__ */ (0,
|
|
2292
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: muted ? "#94a3b8" : "#64748b", fontSize: 12 }, children: [
|
|
2226
2293
|
"ID ",
|
|
2227
2294
|
layerId
|
|
2228
2295
|
] })
|
|
2229
2296
|
] })
|
|
2230
2297
|
] }),
|
|
2231
|
-
/* @__PURE__ */ (0,
|
|
2298
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", alignItems: "flex-start", gap: 6, flexShrink: 0 }, children: typeof featureCount === "number" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "zlm-badge", children: [
|
|
2232
2299
|
featureCount.toLocaleString(),
|
|
2233
2300
|
" features"
|
|
2234
2301
|
] }) })
|
|
2235
2302
|
] }),
|
|
2236
|
-
/* @__PURE__ */ (0,
|
|
2237
|
-
/* @__PURE__ */ (0,
|
|
2238
|
-
/* @__PURE__ */ (0,
|
|
2239
|
-
/* @__PURE__ */ (0,
|
|
2303
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", gap: 10, alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { flex: 1 }, children: [
|
|
2304
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 6, color: "#64748b", fontSize: 12 }, children: [
|
|
2305
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Opacidad" }),
|
|
2306
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
|
|
2240
2307
|
opacityPercent,
|
|
2241
2308
|
"%"
|
|
2242
2309
|
] })
|
|
2243
2310
|
] }),
|
|
2244
|
-
/* @__PURE__ */ (0,
|
|
2311
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2245
2312
|
"input",
|
|
2246
2313
|
{
|
|
2247
2314
|
className: "zlm-range",
|
|
@@ -2279,8 +2346,8 @@ var ZenitLayerManager = ({
|
|
|
2279
2346
|
);
|
|
2280
2347
|
}) });
|
|
2281
2348
|
};
|
|
2282
|
-
return /* @__PURE__ */ (0,
|
|
2283
|
-
/* @__PURE__ */ (0,
|
|
2349
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: ["zenit-layer-manager", className].filter(Boolean).join(" "), style: panelStyle, children: [
|
|
2350
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
|
|
2284
2351
|
.zenit-layer-manager .zlm-card {
|
|
2285
2352
|
transition: box-shadow 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
|
|
2286
2353
|
box-shadow: 0 6px 16px rgba(15, 23, 42, 0.08);
|
|
@@ -2375,16 +2442,16 @@ var ZenitLayerManager = ({
|
|
|
2375
2442
|
outline-offset: 2px;
|
|
2376
2443
|
}
|
|
2377
2444
|
` }),
|
|
2378
|
-
/* @__PURE__ */ (0,
|
|
2379
|
-
/* @__PURE__ */ (0,
|
|
2380
|
-
/* @__PURE__ */ (0,
|
|
2381
|
-
/* @__PURE__ */ (0,
|
|
2382
|
-
/* @__PURE__ */ (0,
|
|
2445
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: headerStyle, children: [
|
|
2446
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
|
|
2447
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
2448
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontWeight: 800, fontSize: 16, color: "#0f172a" }, children: "Gesti\xF3n de Capas" }),
|
|
2449
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: "#64748b", fontSize: 12 }, children: [
|
|
2383
2450
|
"Mapa #",
|
|
2384
2451
|
map.id
|
|
2385
2452
|
] })
|
|
2386
2453
|
] }),
|
|
2387
|
-
/* @__PURE__ */ (0,
|
|
2454
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2388
2455
|
"button",
|
|
2389
2456
|
{
|
|
2390
2457
|
type: "button",
|
|
@@ -2392,13 +2459,13 @@ var ZenitLayerManager = ({
|
|
|
2392
2459
|
className: "zlm-panel-toggle",
|
|
2393
2460
|
"aria-label": panelVisible ? "Ocultar panel de capas" : "Mostrar panel de capas",
|
|
2394
2461
|
children: [
|
|
2395
|
-
panelVisible ? /* @__PURE__ */ (0,
|
|
2462
|
+
panelVisible ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Eye, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.EyeOff, { size: 16 }),
|
|
2396
2463
|
panelVisible ? "Ocultar" : "Mostrar"
|
|
2397
2464
|
]
|
|
2398
2465
|
}
|
|
2399
2466
|
)
|
|
2400
2467
|
] }),
|
|
2401
|
-
/* @__PURE__ */ (0,
|
|
2468
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2402
2469
|
"div",
|
|
2403
2470
|
{
|
|
2404
2471
|
style: {
|
|
@@ -2411,26 +2478,26 @@ var ZenitLayerManager = ({
|
|
|
2411
2478
|
background: "#f1f5f9"
|
|
2412
2479
|
},
|
|
2413
2480
|
children: [
|
|
2414
|
-
/* @__PURE__ */ (0,
|
|
2481
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2415
2482
|
"button",
|
|
2416
2483
|
{
|
|
2417
2484
|
type: "button",
|
|
2418
2485
|
className: `zlm-tab${activeTab === "layers" ? " is-active" : ""}`,
|
|
2419
2486
|
onClick: () => setActiveTab("layers"),
|
|
2420
2487
|
children: [
|
|
2421
|
-
/* @__PURE__ */ (0,
|
|
2488
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Layers, { size: 16 }),
|
|
2422
2489
|
"Capas"
|
|
2423
2490
|
]
|
|
2424
2491
|
}
|
|
2425
2492
|
),
|
|
2426
|
-
showUploadTab && /* @__PURE__ */ (0,
|
|
2493
|
+
showUploadTab && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2427
2494
|
"button",
|
|
2428
2495
|
{
|
|
2429
2496
|
type: "button",
|
|
2430
2497
|
className: `zlm-tab${activeTab === "upload" ? " is-active" : ""}`,
|
|
2431
2498
|
onClick: () => setActiveTab("upload"),
|
|
2432
2499
|
children: [
|
|
2433
|
-
/* @__PURE__ */ (0,
|
|
2500
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Upload, { size: 16 }),
|
|
2434
2501
|
"Subir"
|
|
2435
2502
|
]
|
|
2436
2503
|
}
|
|
@@ -2439,15 +2506,15 @@ var ZenitLayerManager = ({
|
|
|
2439
2506
|
}
|
|
2440
2507
|
)
|
|
2441
2508
|
] }),
|
|
2442
|
-
panelVisible && /* @__PURE__ */ (0,
|
|
2509
|
+
panelVisible && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
|
|
2443
2510
|
activeTab === "layers" && renderLayerCards(),
|
|
2444
|
-
showUploadTab && activeTab === "upload" && /* @__PURE__ */ (0,
|
|
2511
|
+
showUploadTab && activeTab === "upload" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#475569", fontSize: 13 }, children: "Pr\xF3ximamente podr\xE1s subir capas desde este panel." })
|
|
2445
2512
|
] })
|
|
2446
2513
|
] });
|
|
2447
2514
|
};
|
|
2448
2515
|
|
|
2449
2516
|
// src/react/ZenitFeatureFilterPanel.tsx
|
|
2450
|
-
var
|
|
2517
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2451
2518
|
var ZenitFeatureFilterPanel = ({
|
|
2452
2519
|
title = "Filtros",
|
|
2453
2520
|
description,
|
|
@@ -2455,7 +2522,7 @@ var ZenitFeatureFilterPanel = ({
|
|
|
2455
2522
|
style,
|
|
2456
2523
|
children
|
|
2457
2524
|
}) => {
|
|
2458
|
-
return /* @__PURE__ */ (0,
|
|
2525
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2459
2526
|
"section",
|
|
2460
2527
|
{
|
|
2461
2528
|
className,
|
|
@@ -2468,22 +2535,22 @@ var ZenitFeatureFilterPanel = ({
|
|
|
2468
2535
|
...style
|
|
2469
2536
|
},
|
|
2470
2537
|
children: [
|
|
2471
|
-
/* @__PURE__ */ (0,
|
|
2472
|
-
/* @__PURE__ */ (0,
|
|
2473
|
-
description && /* @__PURE__ */ (0,
|
|
2538
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("header", { style: { marginBottom: 12 }, children: [
|
|
2539
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { style: { margin: 0, fontSize: 16 }, children: title }),
|
|
2540
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { style: { margin: "6px 0 0", color: "#475569", fontSize: 13 }, children: description })
|
|
2474
2541
|
] }),
|
|
2475
|
-
/* @__PURE__ */ (0,
|
|
2542
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children })
|
|
2476
2543
|
]
|
|
2477
2544
|
}
|
|
2478
2545
|
);
|
|
2479
2546
|
};
|
|
2480
2547
|
|
|
2481
2548
|
// src/react/ai/FloatingChatBox.tsx
|
|
2482
|
-
var
|
|
2483
|
-
var
|
|
2549
|
+
var import_react7 = require("react");
|
|
2550
|
+
var import_react_dom2 = require("react-dom");
|
|
2484
2551
|
|
|
2485
2552
|
// src/react/hooks/use-chat.ts
|
|
2486
|
-
var
|
|
2553
|
+
var import_react6 = require("react");
|
|
2487
2554
|
|
|
2488
2555
|
// src/ai/chat.service.ts
|
|
2489
2556
|
var DEFAULT_ERROR_MESSAGE = "No fue posible completar la solicitud al asistente.";
|
|
@@ -2615,9 +2682,9 @@ var sendMessageStream = async (mapId, request, callbacks = {}, options, config)
|
|
|
2615
2682
|
|
|
2616
2683
|
// src/react/hooks/use-chat.ts
|
|
2617
2684
|
var useSendMessage = (config) => {
|
|
2618
|
-
const [isLoading, setIsLoading] = (0,
|
|
2619
|
-
const [error, setError] = (0,
|
|
2620
|
-
const send = (0,
|
|
2685
|
+
const [isLoading, setIsLoading] = (0, import_react6.useState)(false);
|
|
2686
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
2687
|
+
const send = (0, import_react6.useCallback)(
|
|
2621
2688
|
async (mapId, request, options) => {
|
|
2622
2689
|
setIsLoading(true);
|
|
2623
2690
|
setError(null);
|
|
@@ -2635,18 +2702,18 @@ var useSendMessage = (config) => {
|
|
|
2635
2702
|
return { sendMessage: send, isLoading, error };
|
|
2636
2703
|
};
|
|
2637
2704
|
var useSendMessageStream = (config) => {
|
|
2638
|
-
const [isStreaming, setIsStreaming] = (0,
|
|
2639
|
-
const [streamingText, setStreamingText] = (0,
|
|
2640
|
-
const [completeResponse, setCompleteResponse] = (0,
|
|
2641
|
-
const [error, setError] = (0,
|
|
2642
|
-
const requestIdRef = (0,
|
|
2643
|
-
const reset = (0,
|
|
2705
|
+
const [isStreaming, setIsStreaming] = (0, import_react6.useState)(false);
|
|
2706
|
+
const [streamingText, setStreamingText] = (0, import_react6.useState)("");
|
|
2707
|
+
const [completeResponse, setCompleteResponse] = (0, import_react6.useState)(null);
|
|
2708
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
2709
|
+
const requestIdRef = (0, import_react6.useRef)(0);
|
|
2710
|
+
const reset = (0, import_react6.useCallback)(() => {
|
|
2644
2711
|
setIsStreaming(false);
|
|
2645
2712
|
setStreamingText("");
|
|
2646
2713
|
setCompleteResponse(null);
|
|
2647
2714
|
setError(null);
|
|
2648
2715
|
}, []);
|
|
2649
|
-
const send = (0,
|
|
2716
|
+
const send = (0, import_react6.useCallback)(
|
|
2650
2717
|
async (mapId, request, options) => {
|
|
2651
2718
|
const requestId = requestIdRef.current + 1;
|
|
2652
2719
|
requestIdRef.current = requestId;
|
|
@@ -2700,7 +2767,7 @@ var useSendMessageStream = (config) => {
|
|
|
2700
2767
|
// src/react/components/MarkdownRenderer.tsx
|
|
2701
2768
|
var import_react_markdown = __toESM(require("react-markdown"));
|
|
2702
2769
|
var import_remark_gfm = __toESM(require("remark-gfm"));
|
|
2703
|
-
var
|
|
2770
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2704
2771
|
function normalizeAssistantMarkdown(text) {
|
|
2705
2772
|
if (!text || typeof text !== "string") return "";
|
|
2706
2773
|
let normalized = text;
|
|
@@ -2716,28 +2783,28 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2716
2783
|
if (!normalizedContent) {
|
|
2717
2784
|
return null;
|
|
2718
2785
|
}
|
|
2719
|
-
return /* @__PURE__ */ (0,
|
|
2786
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className, style: { wordBreak: "break-word" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2720
2787
|
import_react_markdown.default,
|
|
2721
2788
|
{
|
|
2722
2789
|
remarkPlugins: [import_remark_gfm.default],
|
|
2723
2790
|
components: {
|
|
2724
2791
|
// Headings with proper spacing
|
|
2725
|
-
h1: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2726
|
-
h2: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2727
|
-
h3: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2728
|
-
h4: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2729
|
-
h5: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2730
|
-
h6: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2792
|
+
h1: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { style: { fontSize: "1.5em", fontWeight: 700, marginTop: "1em", marginBottom: "0.5em" }, ...props, children }),
|
|
2793
|
+
h2: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { style: { fontSize: "1.3em", fontWeight: 700, marginTop: "0.9em", marginBottom: "0.45em" }, ...props, children }),
|
|
2794
|
+
h3: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { style: { fontSize: "1.15em", fontWeight: 600, marginTop: "0.75em", marginBottom: "0.4em" }, ...props, children }),
|
|
2795
|
+
h4: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h4", { style: { fontSize: "1.05em", fontWeight: 600, marginTop: "0.6em", marginBottom: "0.35em" }, ...props, children }),
|
|
2796
|
+
h5: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h5", { style: { fontSize: "1em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
|
|
2797
|
+
h6: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h6", { style: { fontSize: "0.95em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
|
|
2731
2798
|
// Paragraphs with comfortable line height
|
|
2732
|
-
p: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2799
|
+
p: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: { marginTop: "0.5em", marginBottom: "0.5em", lineHeight: 1.6 }, ...props, children }),
|
|
2733
2800
|
// Lists with proper indentation
|
|
2734
|
-
ul: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2735
|
-
ol: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2736
|
-
li: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2801
|
+
ul: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
|
|
2802
|
+
ol: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ol", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
|
|
2803
|
+
li: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { style: { marginTop: "0.25em", marginBottom: "0.25em" }, ...props, children }),
|
|
2737
2804
|
// Code blocks
|
|
2738
2805
|
code: ({ inline, children, ...props }) => {
|
|
2739
2806
|
if (inline) {
|
|
2740
|
-
return /* @__PURE__ */ (0,
|
|
2807
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2741
2808
|
"code",
|
|
2742
2809
|
{
|
|
2743
2810
|
style: {
|
|
@@ -2752,7 +2819,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2752
2819
|
}
|
|
2753
2820
|
);
|
|
2754
2821
|
}
|
|
2755
|
-
return /* @__PURE__ */ (0,
|
|
2822
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2756
2823
|
"code",
|
|
2757
2824
|
{
|
|
2758
2825
|
style: {
|
|
@@ -2772,9 +2839,9 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2772
2839
|
);
|
|
2773
2840
|
},
|
|
2774
2841
|
// Pre (code block wrapper)
|
|
2775
|
-
pre: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2842
|
+
pre: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { style: { margin: 0 }, ...props, children }),
|
|
2776
2843
|
// Blockquotes
|
|
2777
|
-
blockquote: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2844
|
+
blockquote: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2778
2845
|
"blockquote",
|
|
2779
2846
|
{
|
|
2780
2847
|
style: {
|
|
@@ -2790,11 +2857,11 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2790
2857
|
}
|
|
2791
2858
|
),
|
|
2792
2859
|
// Strong/bold
|
|
2793
|
-
strong: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2860
|
+
strong: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { style: { fontWeight: 600 }, ...props, children }),
|
|
2794
2861
|
// Emphasis/italic
|
|
2795
|
-
em: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2862
|
+
em: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("em", { style: { fontStyle: "italic" }, ...props, children }),
|
|
2796
2863
|
// Horizontal rule
|
|
2797
|
-
hr: (props) => /* @__PURE__ */ (0,
|
|
2864
|
+
hr: (props) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2798
2865
|
"hr",
|
|
2799
2866
|
{
|
|
2800
2867
|
style: {
|
|
@@ -2807,7 +2874,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2807
2874
|
}
|
|
2808
2875
|
),
|
|
2809
2876
|
// Tables (GFM)
|
|
2810
|
-
table: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2877
|
+
table: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { overflowX: "auto", marginTop: "0.5em", marginBottom: "0.5em" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2811
2878
|
"table",
|
|
2812
2879
|
{
|
|
2813
2880
|
style: {
|
|
@@ -2819,7 +2886,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2819
2886
|
children
|
|
2820
2887
|
}
|
|
2821
2888
|
) }),
|
|
2822
|
-
th: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2889
|
+
th: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2823
2890
|
"th",
|
|
2824
2891
|
{
|
|
2825
2892
|
style: {
|
|
@@ -2833,7 +2900,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2833
2900
|
children
|
|
2834
2901
|
}
|
|
2835
2902
|
),
|
|
2836
|
-
td: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2903
|
+
td: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2837
2904
|
"td",
|
|
2838
2905
|
{
|
|
2839
2906
|
style: {
|
|
@@ -2851,32 +2918,32 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2851
2918
|
};
|
|
2852
2919
|
|
|
2853
2920
|
// src/react/ai/FloatingChatBox.tsx
|
|
2854
|
-
var
|
|
2855
|
-
var ChatIcon = () => /* @__PURE__ */ (0,
|
|
2856
|
-
var CloseIcon = () => /* @__PURE__ */ (0,
|
|
2857
|
-
/* @__PURE__ */ (0,
|
|
2858
|
-
/* @__PURE__ */ (0,
|
|
2921
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2922
|
+
var ChatIcon = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
|
|
2923
|
+
var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2924
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
2925
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
2859
2926
|
] });
|
|
2860
|
-
var ExpandIcon = () => /* @__PURE__ */ (0,
|
|
2861
|
-
/* @__PURE__ */ (0,
|
|
2862
|
-
/* @__PURE__ */ (0,
|
|
2863
|
-
/* @__PURE__ */ (0,
|
|
2864
|
-
/* @__PURE__ */ (0,
|
|
2927
|
+
var ExpandIcon = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2928
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "15 3 21 3 21 9" }),
|
|
2929
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "9 21 3 21 3 15" }),
|
|
2930
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
|
|
2931
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
|
|
2865
2932
|
] });
|
|
2866
|
-
var CollapseIcon = () => /* @__PURE__ */ (0,
|
|
2867
|
-
/* @__PURE__ */ (0,
|
|
2868
|
-
/* @__PURE__ */ (0,
|
|
2869
|
-
/* @__PURE__ */ (0,
|
|
2870
|
-
/* @__PURE__ */ (0,
|
|
2933
|
+
var CollapseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2934
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "4 14 10 14 10 20" }),
|
|
2935
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "20 10 14 10 14 4" }),
|
|
2936
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
|
|
2937
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
|
|
2871
2938
|
] });
|
|
2872
|
-
var SendIcon = () => /* @__PURE__ */ (0,
|
|
2873
|
-
/* @__PURE__ */ (0,
|
|
2874
|
-
/* @__PURE__ */ (0,
|
|
2939
|
+
var SendIcon = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2940
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
|
|
2941
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
2875
2942
|
] });
|
|
2876
|
-
var LayersIcon = () => /* @__PURE__ */ (0,
|
|
2877
|
-
/* @__PURE__ */ (0,
|
|
2878
|
-
/* @__PURE__ */ (0,
|
|
2879
|
-
/* @__PURE__ */ (0,
|
|
2943
|
+
var LayersIcon = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2944
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
|
|
2945
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "2 17 12 22 22 17" }),
|
|
2946
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "2 12 12 17 22 12" })
|
|
2880
2947
|
] });
|
|
2881
2948
|
var styles = {
|
|
2882
2949
|
root: {
|
|
@@ -2885,8 +2952,8 @@ var styles = {
|
|
|
2885
2952
|
// Floating button (closed state - wide with text, open state - circular with X)
|
|
2886
2953
|
floatingButton: {
|
|
2887
2954
|
position: "fixed",
|
|
2888
|
-
bottom:
|
|
2889
|
-
right:
|
|
2955
|
+
bottom: 16,
|
|
2956
|
+
right: 16,
|
|
2890
2957
|
borderRadius: "999px",
|
|
2891
2958
|
border: "none",
|
|
2892
2959
|
cursor: "pointer",
|
|
@@ -2896,30 +2963,30 @@ var styles = {
|
|
|
2896
2963
|
display: "flex",
|
|
2897
2964
|
alignItems: "center",
|
|
2898
2965
|
justifyContent: "center",
|
|
2899
|
-
fontSize:
|
|
2966
|
+
fontSize: 14,
|
|
2900
2967
|
fontWeight: 600,
|
|
2901
2968
|
zIndex: 99999,
|
|
2902
2969
|
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
|
|
2903
2970
|
},
|
|
2904
2971
|
floatingButtonClosed: {
|
|
2905
|
-
padding: "
|
|
2972
|
+
padding: "12px 20px",
|
|
2906
2973
|
gap: 8
|
|
2907
2974
|
},
|
|
2908
2975
|
floatingButtonOpen: {
|
|
2909
|
-
width:
|
|
2910
|
-
height:
|
|
2976
|
+
width: 52,
|
|
2977
|
+
height: 52,
|
|
2911
2978
|
padding: 0
|
|
2912
2979
|
},
|
|
2913
2980
|
floatingButtonMobile: {
|
|
2914
|
-
width:
|
|
2915
|
-
height:
|
|
2981
|
+
width: 52,
|
|
2982
|
+
height: 52,
|
|
2916
2983
|
padding: 0
|
|
2917
2984
|
},
|
|
2918
2985
|
// Panel (expandable)
|
|
2919
2986
|
panel: {
|
|
2920
2987
|
position: "fixed",
|
|
2921
|
-
bottom:
|
|
2922
|
-
right:
|
|
2988
|
+
bottom: 80,
|
|
2989
|
+
right: 16,
|
|
2923
2990
|
background: "#fff",
|
|
2924
2991
|
borderRadius: 16,
|
|
2925
2992
|
boxShadow: "0 20px 60px rgba(15, 23, 42, 0.3), 0 0 0 1px rgba(15, 23, 42, 0.05)",
|
|
@@ -2930,16 +2997,16 @@ var styles = {
|
|
|
2930
2997
|
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
|
|
2931
2998
|
},
|
|
2932
2999
|
panelNormal: {
|
|
2933
|
-
width:
|
|
2934
|
-
height:
|
|
3000
|
+
width: 360,
|
|
3001
|
+
height: 520
|
|
2935
3002
|
},
|
|
2936
3003
|
panelExpanded: {
|
|
2937
|
-
width:
|
|
2938
|
-
height:
|
|
3004
|
+
width: 480,
|
|
3005
|
+
height: 640
|
|
2939
3006
|
},
|
|
2940
3007
|
// Header with green gradient
|
|
2941
3008
|
header: {
|
|
2942
|
-
padding: "16px
|
|
3009
|
+
padding: "14px 16px",
|
|
2943
3010
|
background: "linear-gradient(135deg, #10b981, #059669)",
|
|
2944
3011
|
color: "#fff",
|
|
2945
3012
|
display: "flex",
|
|
@@ -2948,7 +3015,7 @@ var styles = {
|
|
|
2948
3015
|
},
|
|
2949
3016
|
title: {
|
|
2950
3017
|
margin: 0,
|
|
2951
|
-
fontSize:
|
|
3018
|
+
fontSize: 15,
|
|
2952
3019
|
fontWeight: 600,
|
|
2953
3020
|
letterSpacing: "-0.01em"
|
|
2954
3021
|
},
|
|
@@ -2961,8 +3028,8 @@ var styles = {
|
|
|
2961
3028
|
border: "none",
|
|
2962
3029
|
background: "rgba(255, 255, 255, 0.15)",
|
|
2963
3030
|
color: "#fff",
|
|
2964
|
-
width:
|
|
2965
|
-
height:
|
|
3031
|
+
width: 30,
|
|
3032
|
+
height: 30,
|
|
2966
3033
|
borderRadius: 8,
|
|
2967
3034
|
cursor: "pointer",
|
|
2968
3035
|
display: "flex",
|
|
@@ -2973,7 +3040,7 @@ var styles = {
|
|
|
2973
3040
|
// Messages area
|
|
2974
3041
|
messages: {
|
|
2975
3042
|
flex: 1,
|
|
2976
|
-
padding: "
|
|
3043
|
+
padding: "16px",
|
|
2977
3044
|
overflowY: "auto",
|
|
2978
3045
|
background: "#f8fafc",
|
|
2979
3046
|
display: "flex",
|
|
@@ -2988,10 +3055,10 @@ var styles = {
|
|
|
2988
3055
|
},
|
|
2989
3056
|
messageBubble: {
|
|
2990
3057
|
maxWidth: "85%",
|
|
2991
|
-
padding: "12px
|
|
3058
|
+
padding: "10px 12px",
|
|
2992
3059
|
borderRadius: 16,
|
|
2993
3060
|
lineHeight: 1.5,
|
|
2994
|
-
fontSize:
|
|
3061
|
+
fontSize: 13,
|
|
2995
3062
|
whiteSpace: "pre-wrap",
|
|
2996
3063
|
wordBreak: "break-word"
|
|
2997
3064
|
},
|
|
@@ -3105,7 +3172,7 @@ var styles = {
|
|
|
3105
3172
|
// Input area
|
|
3106
3173
|
inputWrapper: {
|
|
3107
3174
|
borderTop: "1px solid #e2e8f0",
|
|
3108
|
-
padding: "14px
|
|
3175
|
+
padding: "10px 14px",
|
|
3109
3176
|
display: "flex",
|
|
3110
3177
|
gap: 10,
|
|
3111
3178
|
alignItems: "flex-end",
|
|
@@ -3116,8 +3183,8 @@ var styles = {
|
|
|
3116
3183
|
resize: "none",
|
|
3117
3184
|
borderRadius: 12,
|
|
3118
3185
|
border: "1.5px solid #cbd5e1",
|
|
3119
|
-
padding: "10px
|
|
3120
|
-
fontSize:
|
|
3186
|
+
padding: "8px 10px",
|
|
3187
|
+
fontSize: 13,
|
|
3121
3188
|
fontFamily: "inherit",
|
|
3122
3189
|
lineHeight: 1.4,
|
|
3123
3190
|
transition: "border-color 0.2s"
|
|
@@ -3129,18 +3196,18 @@ var styles = {
|
|
|
3129
3196
|
sendButton: {
|
|
3130
3197
|
borderRadius: 12,
|
|
3131
3198
|
border: "none",
|
|
3132
|
-
padding: "
|
|
3199
|
+
padding: "8px 12px",
|
|
3133
3200
|
background: "linear-gradient(135deg, #10b981, #059669)",
|
|
3134
3201
|
color: "#fff",
|
|
3135
3202
|
cursor: "pointer",
|
|
3136
|
-
fontSize:
|
|
3203
|
+
fontSize: 13,
|
|
3137
3204
|
fontWeight: 600,
|
|
3138
3205
|
display: "flex",
|
|
3139
3206
|
alignItems: "center",
|
|
3140
3207
|
justifyContent: "center",
|
|
3141
3208
|
transition: "opacity 0.2s, transform 0.2s",
|
|
3142
|
-
minWidth:
|
|
3143
|
-
height:
|
|
3209
|
+
minWidth: 40,
|
|
3210
|
+
height: 40
|
|
3144
3211
|
},
|
|
3145
3212
|
// Status messages
|
|
3146
3213
|
statusNote: {
|
|
@@ -3170,42 +3237,42 @@ var FloatingChatBox = ({
|
|
|
3170
3237
|
open: openProp
|
|
3171
3238
|
}) => {
|
|
3172
3239
|
const isControlled = openProp !== void 0;
|
|
3173
|
-
const [internalOpen, setInternalOpen] = (0,
|
|
3240
|
+
const [internalOpen, setInternalOpen] = (0, import_react7.useState)(false);
|
|
3174
3241
|
const open = isControlled ? openProp : internalOpen;
|
|
3175
|
-
const setOpen = (0,
|
|
3242
|
+
const setOpen = (0, import_react7.useCallback)((value) => {
|
|
3176
3243
|
const newValue = typeof value === "function" ? value(open) : value;
|
|
3177
3244
|
if (!isControlled) {
|
|
3178
3245
|
setInternalOpen(newValue);
|
|
3179
3246
|
}
|
|
3180
3247
|
onOpenChange?.(newValue);
|
|
3181
3248
|
}, [isControlled, open, onOpenChange]);
|
|
3182
|
-
const [expanded, setExpanded] = (0,
|
|
3183
|
-
const [messages, setMessages] = (0,
|
|
3184
|
-
const [inputValue, setInputValue] = (0,
|
|
3185
|
-
const [conversationId, setConversationId] = (0,
|
|
3186
|
-
const [errorMessage, setErrorMessage] = (0,
|
|
3187
|
-
const [isFocused, setIsFocused] = (0,
|
|
3188
|
-
const [isMobile, setIsMobile] = (0,
|
|
3189
|
-
const messagesEndRef = (0,
|
|
3190
|
-
const messagesContainerRef = (0,
|
|
3191
|
-
const chatBoxRef = (0,
|
|
3192
|
-
const chatConfig = (0,
|
|
3249
|
+
const [expanded, setExpanded] = (0, import_react7.useState)(false);
|
|
3250
|
+
const [messages, setMessages] = (0, import_react7.useState)([]);
|
|
3251
|
+
const [inputValue, setInputValue] = (0, import_react7.useState)("");
|
|
3252
|
+
const [conversationId, setConversationId] = (0, import_react7.useState)();
|
|
3253
|
+
const [errorMessage, setErrorMessage] = (0, import_react7.useState)(null);
|
|
3254
|
+
const [isFocused, setIsFocused] = (0, import_react7.useState)(false);
|
|
3255
|
+
const [isMobile, setIsMobile] = (0, import_react7.useState)(false);
|
|
3256
|
+
const messagesEndRef = (0, import_react7.useRef)(null);
|
|
3257
|
+
const messagesContainerRef = (0, import_react7.useRef)(null);
|
|
3258
|
+
const chatBoxRef = (0, import_react7.useRef)(null);
|
|
3259
|
+
const chatConfig = (0, import_react7.useMemo)(() => {
|
|
3193
3260
|
if (!baseUrl) return void 0;
|
|
3194
3261
|
return { baseUrl, accessToken, getAccessToken };
|
|
3195
3262
|
}, [accessToken, baseUrl, getAccessToken]);
|
|
3196
3263
|
const { sendMessage: sendMessage2, isStreaming, streamingText, completeResponse } = useSendMessageStream(chatConfig);
|
|
3197
3264
|
const canSend = Boolean(mapId) && Boolean(baseUrl) && inputValue.trim().length > 0 && !isStreaming;
|
|
3198
|
-
(0,
|
|
3265
|
+
(0, import_react7.useEffect)(() => {
|
|
3199
3266
|
if (open && isMobile) {
|
|
3200
3267
|
setExpanded(true);
|
|
3201
3268
|
}
|
|
3202
3269
|
}, [open, isMobile]);
|
|
3203
|
-
const scrollToBottom = (0,
|
|
3270
|
+
const scrollToBottom = (0, import_react7.useCallback)(() => {
|
|
3204
3271
|
if (messagesEndRef.current) {
|
|
3205
3272
|
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
3206
3273
|
}
|
|
3207
3274
|
}, []);
|
|
3208
|
-
(0,
|
|
3275
|
+
(0, import_react7.useEffect)(() => {
|
|
3209
3276
|
if (open && messages.length === 0) {
|
|
3210
3277
|
setMessages([
|
|
3211
3278
|
{
|
|
@@ -3216,10 +3283,10 @@ var FloatingChatBox = ({
|
|
|
3216
3283
|
]);
|
|
3217
3284
|
}
|
|
3218
3285
|
}, [open, messages.length]);
|
|
3219
|
-
(0,
|
|
3286
|
+
(0, import_react7.useEffect)(() => {
|
|
3220
3287
|
scrollToBottom();
|
|
3221
3288
|
}, [messages, streamingText, scrollToBottom]);
|
|
3222
|
-
(0,
|
|
3289
|
+
(0, import_react7.useEffect)(() => {
|
|
3223
3290
|
if (!open) return;
|
|
3224
3291
|
if (isMobile && expanded) return;
|
|
3225
3292
|
const handleClickOutside = (event) => {
|
|
@@ -3232,7 +3299,7 @@ var FloatingChatBox = ({
|
|
|
3232
3299
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
3233
3300
|
};
|
|
3234
3301
|
}, [open, isMobile, expanded]);
|
|
3235
|
-
(0,
|
|
3302
|
+
(0, import_react7.useEffect)(() => {
|
|
3236
3303
|
if (typeof window === "undefined") return;
|
|
3237
3304
|
const mediaQuery = window.matchMedia("(max-width: 768px)");
|
|
3238
3305
|
const updateMobile = () => setIsMobile(mediaQuery.matches);
|
|
@@ -3250,7 +3317,7 @@ var FloatingChatBox = ({
|
|
|
3250
3317
|
}
|
|
3251
3318
|
};
|
|
3252
3319
|
}, []);
|
|
3253
|
-
(0,
|
|
3320
|
+
(0, import_react7.useEffect)(() => {
|
|
3254
3321
|
if (typeof document === "undefined") return;
|
|
3255
3322
|
if (!open || !isMobile) return;
|
|
3256
3323
|
document.body.style.overflow = "hidden";
|
|
@@ -3258,10 +3325,10 @@ var FloatingChatBox = ({
|
|
|
3258
3325
|
document.body.style.overflow = "";
|
|
3259
3326
|
};
|
|
3260
3327
|
}, [open, isMobile]);
|
|
3261
|
-
const addMessage = (0,
|
|
3328
|
+
const addMessage = (0, import_react7.useCallback)((message) => {
|
|
3262
3329
|
setMessages((prev) => [...prev, message]);
|
|
3263
3330
|
}, []);
|
|
3264
|
-
const handleSend = (0,
|
|
3331
|
+
const handleSend = (0, import_react7.useCallback)(async () => {
|
|
3265
3332
|
if (!mapId) {
|
|
3266
3333
|
setErrorMessage("Selecciona un mapa para usar el asistente.");
|
|
3267
3334
|
return;
|
|
@@ -3296,11 +3363,11 @@ var FloatingChatBox = ({
|
|
|
3296
3363
|
response
|
|
3297
3364
|
});
|
|
3298
3365
|
} catch (error) {
|
|
3299
|
-
setErrorMessage(
|
|
3366
|
+
setErrorMessage("Ocurri\xF3 un error al generar la respuesta.");
|
|
3300
3367
|
addMessage({
|
|
3301
3368
|
id: `error-${Date.now()}`,
|
|
3302
3369
|
role: "assistant",
|
|
3303
|
-
content:
|
|
3370
|
+
content: "\u274C Ocurri\xF3 un error al generar la respuesta."
|
|
3304
3371
|
});
|
|
3305
3372
|
}
|
|
3306
3373
|
}, [
|
|
@@ -3314,7 +3381,7 @@ var FloatingChatBox = ({
|
|
|
3314
3381
|
sendMessage2,
|
|
3315
3382
|
userId
|
|
3316
3383
|
]);
|
|
3317
|
-
const handleKeyDown = (0,
|
|
3384
|
+
const handleKeyDown = (0, import_react7.useCallback)(
|
|
3318
3385
|
(event) => {
|
|
3319
3386
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
3320
3387
|
event.preventDefault();
|
|
@@ -3325,20 +3392,20 @@ var FloatingChatBox = ({
|
|
|
3325
3392
|
},
|
|
3326
3393
|
[canSend, handleSend]
|
|
3327
3394
|
);
|
|
3328
|
-
const handleFollowUpClick = (0,
|
|
3395
|
+
const handleFollowUpClick = (0, import_react7.useCallback)((question) => {
|
|
3329
3396
|
setInputValue(question);
|
|
3330
3397
|
}, []);
|
|
3331
3398
|
const renderMetadata = (response) => {
|
|
3332
3399
|
if (!response?.metadata) return null;
|
|
3333
3400
|
const referencedLayers = response.metadata.referencedLayers;
|
|
3334
3401
|
if (!referencedLayers || referencedLayers.length === 0) return null;
|
|
3335
|
-
return /* @__PURE__ */ (0,
|
|
3336
|
-
/* @__PURE__ */ (0,
|
|
3337
|
-
/* @__PURE__ */ (0,
|
|
3402
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.metadataSection, children: [
|
|
3403
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.metadataTitle, children: [
|
|
3404
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LayersIcon, {}),
|
|
3338
3405
|
"Capas Analizadas"
|
|
3339
3406
|
] }),
|
|
3340
|
-
/* @__PURE__ */ (0,
|
|
3341
|
-
/* @__PURE__ */ (0,
|
|
3407
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { style: styles.metadataList, children: referencedLayers.map((layer, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("li", { style: styles.metadataItem, children: [
|
|
3408
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: layer.layerName }),
|
|
3342
3409
|
" (",
|
|
3343
3410
|
layer.featureCount,
|
|
3344
3411
|
" ",
|
|
@@ -3347,7 +3414,7 @@ var FloatingChatBox = ({
|
|
|
3347
3414
|
] }, index)) })
|
|
3348
3415
|
] });
|
|
3349
3416
|
};
|
|
3350
|
-
const handleActionClick = (0,
|
|
3417
|
+
const handleActionClick = (0, import_react7.useCallback)((action) => {
|
|
3351
3418
|
if (isStreaming) return;
|
|
3352
3419
|
setOpen(false);
|
|
3353
3420
|
requestAnimationFrame(() => {
|
|
@@ -3356,9 +3423,9 @@ var FloatingChatBox = ({
|
|
|
3356
3423
|
}, [isStreaming, setOpen, onActionClick]);
|
|
3357
3424
|
const renderActions = (response) => {
|
|
3358
3425
|
if (!response?.suggestedActions?.length) return null;
|
|
3359
|
-
return /* @__PURE__ */ (0,
|
|
3360
|
-
/* @__PURE__ */ (0,
|
|
3361
|
-
/* @__PURE__ */ (0,
|
|
3426
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.actionsSection, children: [
|
|
3427
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.sectionLabel, children: "Acciones Sugeridas" }),
|
|
3428
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.actionsGrid, children: response.suggestedActions.map((action, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3362
3429
|
"button",
|
|
3363
3430
|
{
|
|
3364
3431
|
type: "button",
|
|
@@ -3389,9 +3456,9 @@ var FloatingChatBox = ({
|
|
|
3389
3456
|
};
|
|
3390
3457
|
const renderFollowUps = (response) => {
|
|
3391
3458
|
if (!response?.followUpQuestions?.length) return null;
|
|
3392
|
-
return /* @__PURE__ */ (0,
|
|
3393
|
-
/* @__PURE__ */ (0,
|
|
3394
|
-
/* @__PURE__ */ (0,
|
|
3459
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.actionsSection, children: [
|
|
3460
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.sectionLabel, children: "Preguntas Relacionadas" }),
|
|
3461
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: response.followUpQuestions.map((question, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3395
3462
|
"button",
|
|
3396
3463
|
{
|
|
3397
3464
|
type: "button",
|
|
@@ -3420,8 +3487,8 @@ var FloatingChatBox = ({
|
|
|
3420
3487
|
)) })
|
|
3421
3488
|
] });
|
|
3422
3489
|
};
|
|
3423
|
-
const chatContent = /* @__PURE__ */ (0,
|
|
3424
|
-
/* @__PURE__ */ (0,
|
|
3490
|
+
const chatContent = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.root, children: [
|
|
3491
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `
|
|
3425
3492
|
@keyframes zenitBlink {
|
|
3426
3493
|
0%, 49% { opacity: 1; }
|
|
3427
3494
|
50%, 100% { opacity: 0; }
|
|
@@ -3464,11 +3531,13 @@ var FloatingChatBox = ({
|
|
|
3464
3531
|
@media (max-width: 768px) {
|
|
3465
3532
|
.zenit-chat-panel.zenit-chat-panel--fullscreen {
|
|
3466
3533
|
position: fixed !important;
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3534
|
+
left: 0 !important;
|
|
3535
|
+
right: 0 !important;
|
|
3536
|
+
top: 4rem !important;
|
|
3537
|
+
bottom: 0 !important;
|
|
3538
|
+
width: 100% !important;
|
|
3539
|
+
max-width: 100% !important;
|
|
3540
|
+
height: auto !important;
|
|
3472
3541
|
border-radius: 0 !important;
|
|
3473
3542
|
display: flex !important;
|
|
3474
3543
|
flex-direction: column !important;
|
|
@@ -3491,7 +3560,7 @@ var FloatingChatBox = ({
|
|
|
3491
3560
|
}
|
|
3492
3561
|
}
|
|
3493
3562
|
` }),
|
|
3494
|
-
open && /* @__PURE__ */ (0,
|
|
3563
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3495
3564
|
"div",
|
|
3496
3565
|
{
|
|
3497
3566
|
ref: chatBoxRef,
|
|
@@ -3501,10 +3570,10 @@ var FloatingChatBox = ({
|
|
|
3501
3570
|
...expanded ? styles.panelExpanded : styles.panelNormal
|
|
3502
3571
|
},
|
|
3503
3572
|
children: [
|
|
3504
|
-
/* @__PURE__ */ (0,
|
|
3505
|
-
/* @__PURE__ */ (0,
|
|
3506
|
-
/* @__PURE__ */ (0,
|
|
3507
|
-
/* @__PURE__ */ (0,
|
|
3573
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("header", { style: styles.header, children: [
|
|
3574
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { style: styles.title, children: "Asistente Zenit AI" }),
|
|
3575
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.headerButtons, children: [
|
|
3576
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3508
3577
|
"button",
|
|
3509
3578
|
{
|
|
3510
3579
|
type: "button",
|
|
@@ -3517,10 +3586,10 @@ var FloatingChatBox = ({
|
|
|
3517
3586
|
e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
|
|
3518
3587
|
},
|
|
3519
3588
|
"aria-label": expanded ? "Contraer" : "Expandir",
|
|
3520
|
-
children: expanded ? /* @__PURE__ */ (0,
|
|
3589
|
+
children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CollapseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ExpandIcon, {})
|
|
3521
3590
|
}
|
|
3522
3591
|
),
|
|
3523
|
-
/* @__PURE__ */ (0,
|
|
3592
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3524
3593
|
"button",
|
|
3525
3594
|
{
|
|
3526
3595
|
type: "button",
|
|
@@ -3533,20 +3602,20 @@ var FloatingChatBox = ({
|
|
|
3533
3602
|
e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
|
|
3534
3603
|
},
|
|
3535
3604
|
"aria-label": "Cerrar",
|
|
3536
|
-
children: /* @__PURE__ */ (0,
|
|
3605
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {})
|
|
3537
3606
|
}
|
|
3538
3607
|
)
|
|
3539
3608
|
] })
|
|
3540
3609
|
] }),
|
|
3541
|
-
/* @__PURE__ */ (0,
|
|
3542
|
-
messages.map((message) => /* @__PURE__ */ (0,
|
|
3610
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { ref: messagesContainerRef, className: "zenit-ai-body", style: styles.messages, children: [
|
|
3611
|
+
messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3543
3612
|
"div",
|
|
3544
3613
|
{
|
|
3545
3614
|
style: {
|
|
3546
3615
|
...styles.messageWrapper,
|
|
3547
3616
|
alignItems: message.role === "user" ? "flex-end" : "flex-start"
|
|
3548
3617
|
},
|
|
3549
|
-
children: /* @__PURE__ */ (0,
|
|
3618
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3550
3619
|
"div",
|
|
3551
3620
|
{
|
|
3552
3621
|
style: {
|
|
@@ -3554,7 +3623,7 @@ var FloatingChatBox = ({
|
|
|
3554
3623
|
...message.role === "user" ? styles.userMessage : styles.assistantMessage
|
|
3555
3624
|
},
|
|
3556
3625
|
children: [
|
|
3557
|
-
message.role === "assistant" ? /* @__PURE__ */ (0,
|
|
3626
|
+
message.role === "assistant" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MarkdownRenderer, { content: message.content }) : message.content,
|
|
3558
3627
|
message.role === "assistant" && renderMetadata(message.response),
|
|
3559
3628
|
message.role === "assistant" && renderActions(message.response),
|
|
3560
3629
|
message.role === "assistant" && renderFollowUps(message.response)
|
|
@@ -3564,39 +3633,39 @@ var FloatingChatBox = ({
|
|
|
3564
3633
|
},
|
|
3565
3634
|
message.id
|
|
3566
3635
|
)),
|
|
3567
|
-
isStreaming && /* @__PURE__ */ (0,
|
|
3636
|
+
isStreaming && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3568
3637
|
"div",
|
|
3569
3638
|
{
|
|
3570
3639
|
style: {
|
|
3571
3640
|
...styles.messageWrapper,
|
|
3572
3641
|
alignItems: "flex-start"
|
|
3573
3642
|
},
|
|
3574
|
-
children: /* @__PURE__ */ (0,
|
|
3643
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3575
3644
|
"div",
|
|
3576
3645
|
{
|
|
3577
3646
|
style: {
|
|
3578
3647
|
...styles.messageBubble,
|
|
3579
3648
|
...styles.assistantMessage
|
|
3580
3649
|
},
|
|
3581
|
-
children: streamingText ? /* @__PURE__ */ (0,
|
|
3582
|
-
/* @__PURE__ */ (0,
|
|
3583
|
-
/* @__PURE__ */ (0,
|
|
3584
|
-
] }) : /* @__PURE__ */ (0,
|
|
3585
|
-
/* @__PURE__ */ (0,
|
|
3586
|
-
/* @__PURE__ */ (0,
|
|
3587
|
-
/* @__PURE__ */ (0,
|
|
3588
|
-
/* @__PURE__ */ (0,
|
|
3589
|
-
/* @__PURE__ */ (0,
|
|
3650
|
+
children: streamingText ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
3651
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MarkdownRenderer, { content: streamingText }),
|
|
3652
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.cursor })
|
|
3653
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.thinkingText, children: [
|
|
3654
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Pensando" }),
|
|
3655
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.typingIndicator, children: [
|
|
3656
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
|
|
3657
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
|
|
3658
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot })
|
|
3590
3659
|
] })
|
|
3591
3660
|
] })
|
|
3592
3661
|
}
|
|
3593
3662
|
)
|
|
3594
3663
|
}
|
|
3595
3664
|
),
|
|
3596
|
-
/* @__PURE__ */ (0,
|
|
3665
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: messagesEndRef })
|
|
3597
3666
|
] }),
|
|
3598
|
-
/* @__PURE__ */ (0,
|
|
3599
|
-
/* @__PURE__ */ (0,
|
|
3667
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "zenit-ai-input-area", style: styles.inputWrapper, children: [
|
|
3668
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3600
3669
|
"textarea",
|
|
3601
3670
|
{
|
|
3602
3671
|
style: {
|
|
@@ -3613,7 +3682,7 @@ var FloatingChatBox = ({
|
|
|
3613
3682
|
disabled: !mapId || !baseUrl || isStreaming
|
|
3614
3683
|
}
|
|
3615
3684
|
),
|
|
3616
|
-
/* @__PURE__ */ (0,
|
|
3685
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3617
3686
|
"button",
|
|
3618
3687
|
{
|
|
3619
3688
|
type: "button",
|
|
@@ -3622,36 +3691,38 @@ var FloatingChatBox = ({
|
|
|
3622
3691
|
onClick: () => void handleSend(),
|
|
3623
3692
|
disabled: !canSend,
|
|
3624
3693
|
"aria-label": "Enviar mensaje",
|
|
3625
|
-
children: /* @__PURE__ */ (0,
|
|
3694
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SendIcon, {})
|
|
3626
3695
|
}
|
|
3627
3696
|
)
|
|
3628
3697
|
] }),
|
|
3629
|
-
errorMessage && /* @__PURE__ */ (0,
|
|
3630
|
-
|
|
3631
|
-
!
|
|
3698
|
+
errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.errorText, children: errorMessage }),
|
|
3699
|
+
isStreaming && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.statusNote, children: "Generando sugerencias..." }),
|
|
3700
|
+
!mapId && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.statusNote, children: "Selecciona un mapa para usar el asistente" }),
|
|
3701
|
+
!baseUrl && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.statusNote, children: "Configura la baseUrl del SDK" })
|
|
3632
3702
|
]
|
|
3633
3703
|
}
|
|
3634
3704
|
),
|
|
3635
|
-
!(hideButton && !open) && /* @__PURE__ */ (0,
|
|
3705
|
+
!(hideButton && !open) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3636
3706
|
"button",
|
|
3637
3707
|
{
|
|
3638
3708
|
type: "button",
|
|
3639
3709
|
className: `zenit-ai-button ${open ? "open" : ""}${open && isMobile ? " zenit-ai-button--hidden-mobile" : ""}`,
|
|
3640
3710
|
style: {
|
|
3641
3711
|
...styles.floatingButton,
|
|
3642
|
-
...open ? styles.floatingButtonOpen : isMobile ? styles.floatingButtonMobile : styles.floatingButtonClosed
|
|
3712
|
+
...open ? styles.floatingButtonOpen : isMobile ? styles.floatingButtonMobile : styles.floatingButtonClosed,
|
|
3713
|
+
zIndex: open ? 100001 : 99999
|
|
3643
3714
|
},
|
|
3644
3715
|
onClick: () => setOpen((prev) => !prev),
|
|
3645
3716
|
"aria-label": open ? "Cerrar asistente" : "Abrir asistente Zenit AI",
|
|
3646
|
-
children: open ? /* @__PURE__ */ (0,
|
|
3647
|
-
/* @__PURE__ */ (0,
|
|
3648
|
-
!isMobile && /* @__PURE__ */ (0,
|
|
3717
|
+
children: open ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
3718
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChatIcon, {}),
|
|
3719
|
+
!isMobile && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Asistente IA" })
|
|
3649
3720
|
] })
|
|
3650
3721
|
}
|
|
3651
3722
|
)
|
|
3652
3723
|
] });
|
|
3653
3724
|
if (typeof document !== "undefined") {
|
|
3654
|
-
return (0,
|
|
3725
|
+
return (0, import_react_dom2.createPortal)(chatContent, document.body);
|
|
3655
3726
|
}
|
|
3656
3727
|
return chatContent;
|
|
3657
3728
|
};
|