zenit-sdk 0.1.4 → 0.1.6
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/dist/{chunk-R5WJ7K2D.mjs → chunk-J2YWF2TS.mjs} +548 -168
- package/dist/chunk-J2YWF2TS.mjs.map +1 -0
- package/dist/index.js +521 -141
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/react/index.js +521 -141
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-R5WJ7K2D.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/react/ZenitMap.tsx
|
|
2
|
-
import React4, { useCallback as useCallback2, useEffect as useEffect5, useImperativeHandle, useMemo as
|
|
2
|
+
import React4, { useCallback as useCallback2, useEffect as useEffect5, useImperativeHandle, useMemo as useMemo3, useRef as useRef5, useState as useState2, forwardRef } from "react";
|
|
3
3
|
import { MapContainer, Marker as Marker2, TileLayer, ZoomControl } from "react-leaflet";
|
|
4
4
|
import L4 from "leaflet";
|
|
5
5
|
|
|
@@ -246,11 +246,125 @@ function getEffectiveLayerOpacity(baseOpacity, zoom, layerType, geometryType, op
|
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
// src/react/map/layer-geojson.tsx
|
|
249
|
-
import { useEffect, useRef } from "react";
|
|
249
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
250
250
|
import { GeoJSON } from "react-leaflet";
|
|
251
251
|
import L from "leaflet";
|
|
252
|
+
|
|
253
|
+
// src/react/map/geojson-sanitize.ts
|
|
254
|
+
var warnedKeys = /* @__PURE__ */ new Set();
|
|
255
|
+
function isFiniteNumber(value) {
|
|
256
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
257
|
+
if (typeof value === "string") return Number.isFinite(Number(value));
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
function isValidLonLat(lon, lat) {
|
|
261
|
+
const lonN = typeof lon === "string" ? Number(lon) : lon;
|
|
262
|
+
const latN = typeof lat === "string" ? Number(lat) : lat;
|
|
263
|
+
if (!isFiniteNumber(lonN) || !isFiniteNumber(latN)) return false;
|
|
264
|
+
if (typeof lonN !== "number" || typeof latN !== "number") return false;
|
|
265
|
+
return lonN >= -180 && lonN <= 180 && latN >= -90 && latN <= 90;
|
|
266
|
+
}
|
|
267
|
+
function asFeatureCollection(input) {
|
|
268
|
+
const raw = input && typeof input === "object" && "data" in input ? input.data : input;
|
|
269
|
+
if (!raw || typeof raw !== "object") {
|
|
270
|
+
return { type: "FeatureCollection", features: [] };
|
|
271
|
+
}
|
|
272
|
+
if (raw.type === "FeatureCollection") {
|
|
273
|
+
const collection = raw;
|
|
274
|
+
const features = Array.isArray(collection.features) ? collection.features : [];
|
|
275
|
+
return { ...collection, features };
|
|
276
|
+
}
|
|
277
|
+
if (raw.type === "Feature") {
|
|
278
|
+
return {
|
|
279
|
+
type: "FeatureCollection",
|
|
280
|
+
features: [raw]
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return { type: "FeatureCollection", features: [] };
|
|
284
|
+
}
|
|
285
|
+
function sanitizeFeature(feature) {
|
|
286
|
+
if (!feature || typeof feature !== "object") return null;
|
|
287
|
+
const geometry = feature.geometry;
|
|
288
|
+
if (!geometry || typeof geometry !== "object") return null;
|
|
289
|
+
const geometryType = geometry.type;
|
|
290
|
+
const coordinates = geometry.coordinates;
|
|
291
|
+
if (geometryType === "Point") {
|
|
292
|
+
if (!Array.isArray(coordinates) || coordinates.length < 2) return null;
|
|
293
|
+
return isValidLonLat(coordinates[0], coordinates[1]) ? feature : null;
|
|
294
|
+
}
|
|
295
|
+
if (geometryType === "MultiPoint") {
|
|
296
|
+
if (!Array.isArray(coordinates)) return null;
|
|
297
|
+
const validCoordinates = coordinates.filter((coordinate) => {
|
|
298
|
+
if (!Array.isArray(coordinate) || coordinate.length < 2) return false;
|
|
299
|
+
return isValidLonLat(coordinate[0], coordinate[1]);
|
|
300
|
+
});
|
|
301
|
+
if (validCoordinates.length === 0) return null;
|
|
302
|
+
if (validCoordinates.length === coordinates.length) {
|
|
303
|
+
return feature;
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
...feature,
|
|
307
|
+
geometry: {
|
|
308
|
+
...geometry,
|
|
309
|
+
coordinates: validCoordinates
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
if (geometryType === "LineString" || geometryType === "Polygon" || geometryType === "MultiPolygon" || geometryType === "MultiLineString") {
|
|
314
|
+
return Array.isArray(coordinates) && coordinates.length > 0 ? feature : null;
|
|
315
|
+
}
|
|
316
|
+
return feature;
|
|
317
|
+
}
|
|
318
|
+
function logSanitizeStats(stats, debugKey) {
|
|
319
|
+
if (process.env.NODE_ENV === "production") return;
|
|
320
|
+
if (stats.droppedFeatures === 0 && stats.droppedPointsFromMultiPoint === 0) return;
|
|
321
|
+
const resolvedKey = debugKey ?? "__default__";
|
|
322
|
+
if (warnedKeys.has(resolvedKey)) return;
|
|
323
|
+
warnedKeys.add(resolvedKey);
|
|
324
|
+
console.warn("[zenit-sdk] GeoJSON sanitization dropped invalid geometries.", {
|
|
325
|
+
layerId: debugKey,
|
|
326
|
+
...stats
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
function sanitizeGeoJson(input, debugKey) {
|
|
330
|
+
const featureCollection = asFeatureCollection(input);
|
|
331
|
+
const safeFeatures = [];
|
|
332
|
+
const stats = {
|
|
333
|
+
droppedFeatures: 0,
|
|
334
|
+
droppedPointsFromMultiPoint: 0
|
|
335
|
+
};
|
|
336
|
+
const rawFeatures = Array.isArray(featureCollection.features) ? featureCollection.features : [];
|
|
337
|
+
rawFeatures.forEach((rawFeature) => {
|
|
338
|
+
const feature = rawFeature;
|
|
339
|
+
const geometryType = feature?.geometry?.type;
|
|
340
|
+
const originalCoords = feature?.geometry?.coordinates;
|
|
341
|
+
const sanitized = sanitizeFeature(feature);
|
|
342
|
+
if (!sanitized) {
|
|
343
|
+
stats.droppedFeatures += 1;
|
|
344
|
+
if (geometryType === "MultiPoint" && Array.isArray(originalCoords)) {
|
|
345
|
+
stats.droppedPointsFromMultiPoint += originalCoords.length;
|
|
346
|
+
}
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (geometryType === "MultiPoint" && Array.isArray(originalCoords)) {
|
|
350
|
+
const safeCoords = sanitized.geometry?.coordinates;
|
|
351
|
+
const safeCount = Array.isArray(safeCoords) ? safeCoords.length : 0;
|
|
352
|
+
stats.droppedPointsFromMultiPoint += Math.max(0, originalCoords.length - safeCount);
|
|
353
|
+
}
|
|
354
|
+
safeFeatures.push(sanitized);
|
|
355
|
+
});
|
|
356
|
+
logSanitizeStats(stats, debugKey);
|
|
357
|
+
return {
|
|
358
|
+
...featureCollection,
|
|
359
|
+
type: "FeatureCollection",
|
|
360
|
+
features: safeFeatures
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// src/react/map/layer-geojson.tsx
|
|
252
365
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
253
366
|
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
367
|
+
var DEV_MODE = typeof process !== "undefined" && process.env.NODE_ENV !== "production";
|
|
254
368
|
function normalizeBboxFromData(data) {
|
|
255
369
|
const bboxCandidate = data.bbox;
|
|
256
370
|
if (!Array.isArray(bboxCandidate) || bboxCandidate.length < 4) return null;
|
|
@@ -283,6 +397,45 @@ function isNonPointGeometry(feature) {
|
|
|
283
397
|
const geometryType = getGeometryType(feature);
|
|
284
398
|
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
285
399
|
}
|
|
400
|
+
function isValidLatLng(latlng) {
|
|
401
|
+
const candidate = latlng;
|
|
402
|
+
return Boolean(
|
|
403
|
+
candidate && Number.isFinite(candidate.lat) && Number.isFinite(candidate.lng)
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
function createInvisibleFallbackMarker(latlng) {
|
|
407
|
+
return L.circleMarker(latlng ?? [0, 0], {
|
|
408
|
+
radius: 0,
|
|
409
|
+
opacity: 0,
|
|
410
|
+
fillOpacity: 0,
|
|
411
|
+
interactive: false
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
function createInvisibleFallbackClusterMarker(latlng) {
|
|
415
|
+
return L.marker(latlng ?? [0, 0], {
|
|
416
|
+
opacity: 0,
|
|
417
|
+
interactive: false
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
function ensurePaneName(mapInstance, paneName, fallbackPaneName) {
|
|
421
|
+
if (!mapInstance) return fallbackPaneName;
|
|
422
|
+
const existingPane = mapInstance.getPane(paneName) ?? mapInstance.createPane(paneName);
|
|
423
|
+
if (!existingPane && DEV_MODE) {
|
|
424
|
+
console.warn("[LayerGeoJson] pane unavailable, using fallback", { paneName, fallbackPaneName });
|
|
425
|
+
}
|
|
426
|
+
return mapInstance.getPane(paneName) ? paneName : fallbackPaneName;
|
|
427
|
+
}
|
|
428
|
+
function createPointDivIcon(style, isMobile) {
|
|
429
|
+
const size = isMobile ? 18 : 14;
|
|
430
|
+
const backgroundColor = style.fillColor ?? style.color ?? "#3388ff";
|
|
431
|
+
const borderColor = style.color ?? style.fillColor ?? "#3388ff";
|
|
432
|
+
return L.divIcon({
|
|
433
|
+
className: "zenit-point-marker",
|
|
434
|
+
html: `<div style="width:${size}px;height:${size}px;border-radius:50%;background:${backgroundColor};border:2px solid ${borderColor};"></div>`,
|
|
435
|
+
iconSize: [size, size],
|
|
436
|
+
iconAnchor: [size / 2, size / 2]
|
|
437
|
+
});
|
|
438
|
+
}
|
|
286
439
|
function buildFeatureCollection(features) {
|
|
287
440
|
return {
|
|
288
441
|
type: "FeatureCollection",
|
|
@@ -303,14 +456,15 @@ var LayerGeoJson = ({
|
|
|
303
456
|
onEachFeature,
|
|
304
457
|
onPolygonLabel
|
|
305
458
|
}) => {
|
|
306
|
-
const
|
|
307
|
-
const
|
|
308
|
-
const
|
|
459
|
+
const safeData = useMemo(() => sanitizeGeoJson(data, String(layerId)), [data, layerId]);
|
|
460
|
+
const features = useMemo(() => safeData.features ?? [], [safeData]);
|
|
461
|
+
const fillFeatures = useMemo(() => features.filter(isNonPointGeometry), [features]);
|
|
462
|
+
const pointFeatures = useMemo(() => features.filter(isPointGeometry), [features]);
|
|
309
463
|
const dataVersionRef = useRef(0);
|
|
310
464
|
const prevSignatureRef = useRef("");
|
|
311
465
|
const firstId = features.length > 0 ? String(features[0]?.id ?? "") : "";
|
|
312
466
|
const lastId = features.length > 0 ? String(features[features.length - 1]?.id ?? "") : "";
|
|
313
|
-
const bbox = normalizeBboxFromData(
|
|
467
|
+
const bbox = normalizeBboxFromData(safeData);
|
|
314
468
|
const idsSample = buildIdsSample(features);
|
|
315
469
|
const signature = bbox ? `${layerId}|${features.length}|${firstId}|${lastId}|${idsSample}|${bbox[0]}|${bbox[1]}|${bbox[2]}|${bbox[3]}` : `${layerId}|${features.length}|${firstId}|${lastId}|${idsSample}`;
|
|
316
470
|
const signatureToken = signature.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
@@ -318,25 +472,40 @@ var LayerGeoJson = ({
|
|
|
318
472
|
dataVersionRef.current += 1;
|
|
319
473
|
prevSignatureRef.current = signature;
|
|
320
474
|
}
|
|
321
|
-
const fillData = fillFeatures.length > 0 ? buildFeatureCollection(fillFeatures) : null;
|
|
322
|
-
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
475
|
+
const fillData = useMemo(() => fillFeatures.length > 0 ? buildFeatureCollection(fillFeatures) : null, [fillFeatures]);
|
|
476
|
+
const pointsData = useMemo(() => pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null, [pointFeatures]);
|
|
323
477
|
const clusterLayerRef = useRef(null);
|
|
324
478
|
const canCluster = typeof L.markerClusterGroup === "function";
|
|
479
|
+
const resolvedFillPane = useMemo(
|
|
480
|
+
() => ensurePaneName(mapInstance, fillPaneName, "overlayPane"),
|
|
481
|
+
[fillPaneName, mapInstance]
|
|
482
|
+
);
|
|
483
|
+
const resolvedPointsPane = useMemo(
|
|
484
|
+
() => ensurePaneName(mapInstance, pointsPaneName, "markerPane"),
|
|
485
|
+
[mapInstance, pointsPaneName]
|
|
486
|
+
);
|
|
325
487
|
useEffect(() => {
|
|
326
488
|
if (!mapInstance || !panesReady || !pointsData || !canCluster) return;
|
|
327
489
|
const markerClusterGroup = L.markerClusterGroup;
|
|
328
|
-
const
|
|
490
|
+
const clusterPaneName = resolvedPointsPane;
|
|
491
|
+
const clusterLayer = clusterLayerRef.current ?? markerClusterGroup({ pane: clusterPaneName, clusterPane: clusterPaneName });
|
|
329
492
|
clusterLayerRef.current = clusterLayer;
|
|
330
493
|
if (!mapInstance.hasLayer(clusterLayer)) {
|
|
331
494
|
mapInstance.addLayer(clusterLayer);
|
|
332
495
|
}
|
|
333
496
|
clusterLayer.clearLayers();
|
|
334
497
|
const geoJsonLayer = L.geoJSON(pointsData, {
|
|
335
|
-
pointToLayer: (feature, latlng) =>
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
498
|
+
pointToLayer: (feature, latlng) => {
|
|
499
|
+
if (!isValidLatLng(latlng)) {
|
|
500
|
+
return createInvisibleFallbackClusterMarker();
|
|
501
|
+
}
|
|
502
|
+
const style = styleFn(feature, layerType, baseOpacity);
|
|
503
|
+
return L.marker(latlng, {
|
|
504
|
+
icon: createPointDivIcon(style, isMobile),
|
|
505
|
+
pane: clusterPaneName,
|
|
506
|
+
interactive: true
|
|
507
|
+
});
|
|
508
|
+
},
|
|
340
509
|
onEachFeature
|
|
341
510
|
});
|
|
342
511
|
clusterLayer.addLayer(geoJsonLayer);
|
|
@@ -355,7 +524,7 @@ var LayerGeoJson = ({
|
|
|
355
524
|
onEachFeature,
|
|
356
525
|
panesReady,
|
|
357
526
|
pointsData,
|
|
358
|
-
|
|
527
|
+
resolvedPointsPane,
|
|
359
528
|
styleFn
|
|
360
529
|
]);
|
|
361
530
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -363,7 +532,7 @@ var LayerGeoJson = ({
|
|
|
363
532
|
GeoJSON,
|
|
364
533
|
{
|
|
365
534
|
data: fillData,
|
|
366
|
-
pane:
|
|
535
|
+
pane: resolvedFillPane,
|
|
367
536
|
style: (feature) => styleFn(feature, layerType, baseOpacity),
|
|
368
537
|
onEachFeature: (feature, layer) => {
|
|
369
538
|
onEachFeature(feature, layer);
|
|
@@ -376,11 +545,16 @@ var LayerGeoJson = ({
|
|
|
376
545
|
GeoJSON,
|
|
377
546
|
{
|
|
378
547
|
data: pointsData,
|
|
379
|
-
pane:
|
|
380
|
-
pointToLayer: (feature, latlng) =>
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
548
|
+
pane: resolvedPointsPane,
|
|
549
|
+
pointToLayer: (feature, latlng) => {
|
|
550
|
+
if (!isValidLatLng(latlng)) {
|
|
551
|
+
return createInvisibleFallbackMarker();
|
|
552
|
+
}
|
|
553
|
+
return L.circleMarker(latlng, {
|
|
554
|
+
radius: isMobile ? 8 : 6,
|
|
555
|
+
...styleFn(feature, layerType, baseOpacity)
|
|
556
|
+
});
|
|
557
|
+
},
|
|
384
558
|
onEachFeature
|
|
385
559
|
},
|
|
386
560
|
`points-${layerId}-${signatureToken}-v${dataVersionRef.current}`
|
|
@@ -389,7 +563,7 @@ var LayerGeoJson = ({
|
|
|
389
563
|
};
|
|
390
564
|
|
|
391
565
|
// src/react/map/location-control.tsx
|
|
392
|
-
import { useEffect as useEffect3, useMemo, useRef as useRef3 } from "react";
|
|
566
|
+
import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef3 } from "react";
|
|
393
567
|
import { createPortal } from "react-dom";
|
|
394
568
|
import { Circle, Marker, useMap } from "react-leaflet";
|
|
395
569
|
import L3 from "leaflet";
|
|
@@ -462,7 +636,22 @@ function useGeolocation(options) {
|
|
|
462
636
|
import L2 from "leaflet";
|
|
463
637
|
var POPUP_STYLE_ID = "zenit-leaflet-popup-styles";
|
|
464
638
|
var POPUP_EXCLUDED_KEYS = /* @__PURE__ */ new Set(["geom", "geometry", "_private"]);
|
|
465
|
-
var
|
|
639
|
+
var POPUP_TITLE_KEYS = ["id", "nombre", "name", "title", "titulo", "cluster"];
|
|
640
|
+
var POPUP_BADGE_KEYS = ["tipo", "type", "category", "categoria", "estado", "status"];
|
|
641
|
+
var POPUP_DESCRIPTION_KEYS = ["descripcion", "description", "desc"];
|
|
642
|
+
var CURRENCY_KEYWORDS = [
|
|
643
|
+
"capital",
|
|
644
|
+
"monto",
|
|
645
|
+
"precio",
|
|
646
|
+
"costo",
|
|
647
|
+
"valor",
|
|
648
|
+
"ingreso",
|
|
649
|
+
"egreso",
|
|
650
|
+
"saldo",
|
|
651
|
+
"subtotal",
|
|
652
|
+
"venta",
|
|
653
|
+
"compra"
|
|
654
|
+
];
|
|
466
655
|
var DESKTOP_POPUP_DIMENSIONS = { maxWidth: 360, minWidth: 280, maxHeight: 520 };
|
|
467
656
|
var MOBILE_POPUP_DIMENSIONS = { maxWidth: 300, minWidth: 240, maxHeight: 420 };
|
|
468
657
|
var ZENIT_LEAFLET_POPUP_STYLES = `
|
|
@@ -580,6 +769,68 @@ function escapeHtml(value) {
|
|
|
580
769
|
function formatLabel(key) {
|
|
581
770
|
return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").trim();
|
|
582
771
|
}
|
|
772
|
+
function isHexColor(value) {
|
|
773
|
+
return /^#([0-9A-F]{3}){1,2}$/i.test(value.trim());
|
|
774
|
+
}
|
|
775
|
+
function isCurrencyField(key) {
|
|
776
|
+
const normalized = key.trim().toLowerCase();
|
|
777
|
+
return CURRENCY_KEYWORDS.some((keyword) => normalized.includes(keyword));
|
|
778
|
+
}
|
|
779
|
+
function formatCurrency(value) {
|
|
780
|
+
return new Intl.NumberFormat("es-GT", { style: "currency", currency: "GTQ" }).format(value);
|
|
781
|
+
}
|
|
782
|
+
function getBadgeForProperty(key, value) {
|
|
783
|
+
if (value === null || value === void 0) return null;
|
|
784
|
+
const normalizedKey = key.trim().toLowerCase();
|
|
785
|
+
const normalizedValue = String(value).trim().toLowerCase();
|
|
786
|
+
const byType = {
|
|
787
|
+
mora: { label: "Mora", bg: "#fee2e2", color: "#b91c1c", border: "#fecaca" },
|
|
788
|
+
castigo: { label: "Castigo", bg: "#ffedd5", color: "#c2410c", border: "#fed7aa" },
|
|
789
|
+
colocacion: { label: "Colocaci\xF3n", bg: "#dbeafe", color: "#1d4ed8", border: "#bfdbfe" },
|
|
790
|
+
sano: { label: "Sano", bg: "#dcfce7", color: "#15803d", border: "#bbf7d0" }
|
|
791
|
+
};
|
|
792
|
+
const byStatus = {
|
|
793
|
+
activo: { label: "Activo", bg: "#dcfce7", color: "#15803d", border: "#bbf7d0" },
|
|
794
|
+
inactivo: { label: "Inactivo", bg: "#fef9c3", color: "#a16207", border: "#fde68a" },
|
|
795
|
+
pendiente: { label: "Pendiente", bg: "#fef9c3", color: "#a16207", border: "#fde68a" },
|
|
796
|
+
cancelado: { label: "Cancelado", bg: "#fee2e2", color: "#b91c1c", border: "#fecaca" },
|
|
797
|
+
rechazado: { label: "Rechazado", bg: "#fee2e2", color: "#b91c1c", border: "#fecaca" }
|
|
798
|
+
};
|
|
799
|
+
if (["tipo", "type", "category", "categoria"].includes(normalizedKey)) {
|
|
800
|
+
return byType[normalizedValue] ?? {
|
|
801
|
+
label: String(value),
|
|
802
|
+
bg: "#e0e7ff",
|
|
803
|
+
color: "#4338ca",
|
|
804
|
+
border: "#c7d2fe"
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
if (["estado", "status"].includes(normalizedKey)) {
|
|
808
|
+
return byStatus[normalizedValue] ?? {
|
|
809
|
+
label: String(value),
|
|
810
|
+
bg: "#f1f5f9",
|
|
811
|
+
color: "#475569",
|
|
812
|
+
border: "#cbd5e1"
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
return null;
|
|
816
|
+
}
|
|
817
|
+
function findHeaderProperties(properties) {
|
|
818
|
+
const entries = Object.entries(properties);
|
|
819
|
+
const titleEntry = entries.find(
|
|
820
|
+
([key, value]) => POPUP_TITLE_KEYS.includes(key.trim().toLowerCase()) && String(value ?? "").trim().length > 0
|
|
821
|
+
);
|
|
822
|
+
const badgeEntry = entries.find(
|
|
823
|
+
([key, value]) => POPUP_BADGE_KEYS.includes(key.trim().toLowerCase()) && String(value ?? "").trim().length > 0
|
|
824
|
+
);
|
|
825
|
+
const descriptionEntry = entries.find(
|
|
826
|
+
([key, value]) => POPUP_DESCRIPTION_KEYS.includes(key.trim().toLowerCase()) && String(value ?? "").trim().length > 0
|
|
827
|
+
);
|
|
828
|
+
return {
|
|
829
|
+
title: titleEntry ? { key: titleEntry[0], value: String(titleEntry[1]).trim() } : void 0,
|
|
830
|
+
badge: badgeEntry ? { key: badgeEntry[0], value: badgeEntry[1] } : void 0,
|
|
831
|
+
description: descriptionEntry ? { key: descriptionEntry[0], value: String(descriptionEntry[1]).trim() } : void 0
|
|
832
|
+
};
|
|
833
|
+
}
|
|
583
834
|
function renderPopupValue(value) {
|
|
584
835
|
if (value === null || value === void 0) return '<span style="color:#94a3b8;">Sin datos</span>';
|
|
585
836
|
if (value instanceof Date) {
|
|
@@ -605,12 +856,8 @@ function renderPopupValue(value) {
|
|
|
605
856
|
return escapeHtml(String(value));
|
|
606
857
|
}
|
|
607
858
|
function extractPopupHeader(properties) {
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
const normalized = key.trim().toLowerCase();
|
|
611
|
-
return POPUP_HEADER_KEYS.includes(normalized) && value.trim().length > 0;
|
|
612
|
-
});
|
|
613
|
-
return entry ? entry[1].trim() : null;
|
|
859
|
+
const header = findHeaderProperties(properties);
|
|
860
|
+
return header.title?.value ?? null;
|
|
614
861
|
}
|
|
615
862
|
function shouldIncludePopupEntry(key, value) {
|
|
616
863
|
if (!key) return false;
|
|
@@ -623,21 +870,36 @@ function shouldIncludePopupEntry(key, value) {
|
|
|
623
870
|
return true;
|
|
624
871
|
}
|
|
625
872
|
function createPopupContent(properties) {
|
|
626
|
-
const
|
|
873
|
+
const header = findHeaderProperties(properties);
|
|
874
|
+
const headerText = header.title?.value ?? extractPopupHeader(properties);
|
|
875
|
+
const usedKeys = new Set([header.title?.key, header.badge?.key, header.description?.key].filter(Boolean));
|
|
876
|
+
const badge = header.badge ? getBadgeForProperty(header.badge.key, header.badge.value) : null;
|
|
877
|
+
const colorValue = properties.color;
|
|
878
|
+
const colorBar = typeof colorValue === "string" && isHexColor(colorValue) ? `<div style="height:6px; border-radius:8px; margin:-2px -2px 10px; background:linear-gradient(90deg, ${colorValue}, rgba(255,255,255,0.95));"></div>` : "";
|
|
627
879
|
const entries = Object.entries(properties).filter(([key, value]) => {
|
|
628
880
|
if (!shouldIncludePopupEntry(key, value)) return false;
|
|
629
|
-
if (
|
|
881
|
+
if (usedKeys.has(key)) return false;
|
|
630
882
|
return true;
|
|
631
883
|
});
|
|
632
884
|
if (entries.length === 0) {
|
|
633
885
|
return '<div style="padding:8px 0; color:#64748b; text-align:center;">Sin datos disponibles</div>';
|
|
634
886
|
}
|
|
635
|
-
const headerHtml = headerText ? `<div style="
|
|
636
|
-
|
|
887
|
+
const headerHtml = headerText || badge ? `<div style="display:flex; justify-content:space-between; gap:8px; align-items:flex-start; margin-bottom:8px;">
|
|
888
|
+
<div style="font-weight:700; font-size:14px; color:#0f172a;">${escapeHtml(headerText ?? "Detalle")}</div>
|
|
889
|
+
${badge ? `<span style="display:inline-flex; padding:2px 8px; border-radius:999px; font-size:11px; font-weight:700; background:${badge.bg}; color:${badge.color}; border:1px solid ${badge.border}; white-space:nowrap;">${escapeHtml(
|
|
890
|
+
badge.label
|
|
891
|
+
)}</span>` : ""}
|
|
892
|
+
</div>` : "";
|
|
893
|
+
const descriptionHtml = header.description ? `<div style="margin-bottom:10px; padding:8px 10px; background:#f8fafc; border-left:3px solid #38bdf8; border-radius:6px; color:#334155; font-size:12px;">${escapeHtml(
|
|
894
|
+
header.description.value
|
|
637
895
|
)}</div>` : "";
|
|
638
896
|
const rowsHtml = entries.map(([key, value]) => {
|
|
639
897
|
const label = escapeHtml(formatLabel(key));
|
|
640
|
-
const
|
|
898
|
+
const normalizedKey = key.trim().toLowerCase();
|
|
899
|
+
let valueHtml = renderPopupValue(value);
|
|
900
|
+
if (typeof value === "number") {
|
|
901
|
+
valueHtml = isCurrencyField(normalizedKey) ? `<span style="color:#15803d; font-weight:700;">${escapeHtml(formatCurrency(value))}</span>` : `<span style="color:#0369a1; font-weight:600;">${escapeHtml(value.toLocaleString("es-GT"))}</span>`;
|
|
902
|
+
}
|
|
641
903
|
return `
|
|
642
904
|
<div style="display:grid; grid-template-columns:minmax(90px, 35%) 1fr; gap:8px; padding:6px 0; border-bottom:1px solid #e2e8f0;">
|
|
643
905
|
<div style="font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.04em; color:#64748b;">${label}</div>
|
|
@@ -645,7 +907,7 @@ function createPopupContent(properties) {
|
|
|
645
907
|
</div>
|
|
646
908
|
`;
|
|
647
909
|
}).join("");
|
|
648
|
-
return `<div>${headerHtml}${rowsHtml}</div>`;
|
|
910
|
+
return `<div>${colorBar}${headerHtml}${descriptionHtml}${rowsHtml}</div>`;
|
|
649
911
|
}
|
|
650
912
|
function isPolygonType(layerType, geometryType) {
|
|
651
913
|
const candidate = (layerType ?? geometryType ?? "").toLowerCase();
|
|
@@ -655,21 +917,27 @@ function calculateZoomBasedOpacity(zoom, baseOpacity, layerType, geometryType) {
|
|
|
655
917
|
if (!isPolygonType(layerType, geometryType)) return clampOpacity4(baseOpacity);
|
|
656
918
|
const minZoom = 11;
|
|
657
919
|
const maxZoom = 15;
|
|
658
|
-
const minFactor = 0.
|
|
920
|
+
const minFactor = 0.5;
|
|
659
921
|
if (maxZoom <= minZoom) return clampOpacity4(baseOpacity * minFactor);
|
|
660
922
|
const t = clampNumber2((zoom - minZoom) / (maxZoom - minZoom), 0, 1);
|
|
661
923
|
const factor = 1 - (1 - minFactor) * t;
|
|
662
924
|
return clampOpacity4(baseOpacity * factor);
|
|
663
925
|
}
|
|
664
926
|
function layerStyleToLeaflet(options) {
|
|
665
|
-
const { baseOpacity, zoom, layerStyle, geometryType, layerType } = options;
|
|
927
|
+
const { baseOpacity, zoom, layerStyle, geometryType, layerType, properties } = options;
|
|
666
928
|
const sanitizedOpacity = clampOpacity4(baseOpacity);
|
|
667
929
|
const zoomOpacity = calculateZoomBasedOpacity(zoom, sanitizedOpacity, layerType, geometryType);
|
|
668
|
-
const
|
|
930
|
+
const badgeForType = getBadgeForProperty("type", properties?.type ?? properties?.tipo ?? properties?.category ?? properties?.categoria);
|
|
931
|
+
const badgeForStatus = getBadgeForProperty("status", properties?.status ?? properties?.estado);
|
|
932
|
+
const featureColor = (typeof properties?.color === "string" && properties.color.trim().length > 0 ? properties.color : void 0) ?? badgeForType?.color ?? badgeForStatus?.color;
|
|
933
|
+
const styleFillOpacity = typeof layerStyle?.fillOpacity === "number" ? clampOpacity4(layerStyle.fillOpacity) : 0.65;
|
|
934
|
+
const fallbackColor = "#2563eb";
|
|
935
|
+
const resolvedColor = featureColor ?? layerStyle?.color ?? layerStyle?.fillColor ?? fallbackColor;
|
|
936
|
+
const resolvedFillColor = featureColor ?? layerStyle?.fillColor ?? layerStyle?.color ?? fallbackColor;
|
|
669
937
|
return {
|
|
670
|
-
color:
|
|
938
|
+
color: resolvedColor,
|
|
671
939
|
weight: layerStyle?.weight ?? 2,
|
|
672
|
-
fillColor:
|
|
940
|
+
fillColor: resolvedFillColor,
|
|
673
941
|
opacity: clampOpacity4(Math.max(0.35, zoomOpacity * 0.9)),
|
|
674
942
|
fillOpacity: clampOpacity4(zoomOpacity * styleFillOpacity)
|
|
675
943
|
};
|
|
@@ -900,7 +1168,7 @@ var LocationControl = ({ position = "bottomleft", zoom = 16 }) => {
|
|
|
900
1168
|
hasCenteredRef.current = true;
|
|
901
1169
|
map.flyTo([location.lat, location.lon], zoom, { animate: true });
|
|
902
1170
|
}, [isTracking, location, map, zoom]);
|
|
903
|
-
const markerIcon =
|
|
1171
|
+
const markerIcon = useMemo2(() => createLocationIcon(), []);
|
|
904
1172
|
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
905
1173
|
controlRef.current && createPortal(
|
|
906
1174
|
/* @__PURE__ */ jsxs2("div", { children: [
|
|
@@ -1067,6 +1335,7 @@ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
|
1067
1335
|
var DEFAULT_CENTER = [0, 0];
|
|
1068
1336
|
var DEFAULT_ZOOM = 3;
|
|
1069
1337
|
var LABELS_PANE_NAME = "zenit-labels-pane";
|
|
1338
|
+
var DEV_MODE2 = typeof process !== "undefined" && process.env.NODE_ENV !== "production";
|
|
1070
1339
|
function isRecord(value) {
|
|
1071
1340
|
return typeof value === "object" && value !== null;
|
|
1072
1341
|
}
|
|
@@ -1090,6 +1359,8 @@ function getFeatureLayerId(feature) {
|
|
|
1090
1359
|
return layerId;
|
|
1091
1360
|
}
|
|
1092
1361
|
var DESCRIPTION_KEYS = /* @__PURE__ */ new Set(["descripcion", "description"]);
|
|
1362
|
+
var POINT_GEOMETRY_TYPES2 = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
1363
|
+
var POLYGON_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Polygon", "MultiPolygon"]);
|
|
1093
1364
|
function normalizeDescriptionValue(value) {
|
|
1094
1365
|
if (value === void 0 || value === null) return null;
|
|
1095
1366
|
if (typeof value === "string") {
|
|
@@ -1109,6 +1380,31 @@ function extractDescriptionValue(properties) {
|
|
|
1109
1380
|
if (!matches) return null;
|
|
1110
1381
|
return normalizeDescriptionValue(matches[1]);
|
|
1111
1382
|
}
|
|
1383
|
+
function normalizeLayerId(value) {
|
|
1384
|
+
if (value === null || value === void 0) return null;
|
|
1385
|
+
const normalized = String(value).trim();
|
|
1386
|
+
return normalized ? normalized : null;
|
|
1387
|
+
}
|
|
1388
|
+
function isLayerIdMatch(a, b) {
|
|
1389
|
+
const normalizedA = normalizeLayerId(a);
|
|
1390
|
+
const normalizedB = normalizeLayerId(b);
|
|
1391
|
+
return normalizedA !== null && normalizedB !== null && normalizedA === normalizedB;
|
|
1392
|
+
}
|
|
1393
|
+
function getClickIntent(params) {
|
|
1394
|
+
const geometryType = params.feature?.geometry?.type;
|
|
1395
|
+
if (geometryType && POINT_GEOMETRY_TYPES2.has(geometryType)) return "point";
|
|
1396
|
+
if (params.leafletLayer instanceof L4.Marker) return "point";
|
|
1397
|
+
if (geometryType && POLYGON_GEOMETRY_TYPES.has(geometryType)) return "polygon";
|
|
1398
|
+
if (params.leafletLayer instanceof L4.Path) return "polygon";
|
|
1399
|
+
return "unknown";
|
|
1400
|
+
}
|
|
1401
|
+
function candidateLayerId(candidate) {
|
|
1402
|
+
return getFeatureLayerId(candidate);
|
|
1403
|
+
}
|
|
1404
|
+
function isCandidateGeometryType(candidate, allowedTypes) {
|
|
1405
|
+
const geometryType = candidate?.geometry?.type;
|
|
1406
|
+
return Boolean(geometryType && allowedTypes.has(geometryType));
|
|
1407
|
+
}
|
|
1112
1408
|
function getFeatureStyleOverrides(feature) {
|
|
1113
1409
|
const candidate = feature?.properties?._style;
|
|
1114
1410
|
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return null;
|
|
@@ -1126,17 +1422,50 @@ function buildFeaturePopupHtml(feature) {
|
|
|
1126
1422
|
const rendered = createPopupContent(properties);
|
|
1127
1423
|
return rendered ? rendered : null;
|
|
1128
1424
|
}
|
|
1129
|
-
function pickIntersectFeature(
|
|
1425
|
+
function pickIntersectFeature(params) {
|
|
1426
|
+
const { baseFeature, candidates, expectedLayerId, clickIntent } = params;
|
|
1130
1427
|
if (!Array.isArray(candidates) || candidates.length === 0) return null;
|
|
1428
|
+
const pickByGeometry = (pool, intent) => {
|
|
1429
|
+
const preferredTypes = intent === "point" ? POINT_GEOMETRY_TYPES2 : intent === "polygon" ? POLYGON_GEOMETRY_TYPES : null;
|
|
1430
|
+
if (!preferredTypes) return null;
|
|
1431
|
+
const found = pool.find((candidate) => isCandidateGeometryType(candidate, preferredTypes));
|
|
1432
|
+
if (!found) return null;
|
|
1433
|
+
return { feature: found, reason: `geometry:${intent}` };
|
|
1434
|
+
};
|
|
1435
|
+
const getResult = (feature, reason) => ({
|
|
1436
|
+
feature,
|
|
1437
|
+
selectedIdx: candidates.findIndex((candidate) => candidate === feature),
|
|
1438
|
+
reason
|
|
1439
|
+
});
|
|
1440
|
+
const sameLayer = candidates.filter(
|
|
1441
|
+
(candidate) => isLayerIdMatch(candidateLayerId(candidate), expectedLayerId)
|
|
1442
|
+
);
|
|
1443
|
+
const geometryFromSameLayer = pickByGeometry(sameLayer, clickIntent);
|
|
1444
|
+
if (geometryFromSameLayer?.feature) {
|
|
1445
|
+
return getResult(geometryFromSameLayer.feature, `sameLayer>${geometryFromSameLayer.reason}`);
|
|
1446
|
+
}
|
|
1447
|
+
if (sameLayer.length > 0) {
|
|
1448
|
+
const sameLayerWithDescription = sameLayer.find(
|
|
1449
|
+
(candidate) => extractDescriptionValue(candidate?.properties)
|
|
1450
|
+
);
|
|
1451
|
+
if (sameLayerWithDescription) {
|
|
1452
|
+
return getResult(sameLayerWithDescription, "sameLayer>description");
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
const geometryFallback = pickByGeometry(candidates, clickIntent);
|
|
1456
|
+
if (geometryFallback?.feature) {
|
|
1457
|
+
return getResult(geometryFallback.feature, `anyLayer>${geometryFallback.reason}`);
|
|
1458
|
+
}
|
|
1131
1459
|
const baseId = baseFeature?.id;
|
|
1132
1460
|
if (baseId !== void 0 && baseId !== null) {
|
|
1133
1461
|
const matchById = candidates.find((candidate) => candidate?.id === baseId);
|
|
1134
|
-
if (matchById) return matchById;
|
|
1462
|
+
if (matchById) return getResult(matchById, "fallback>baseId");
|
|
1135
1463
|
}
|
|
1136
1464
|
const matchWithDescription = candidates.find(
|
|
1137
1465
|
(candidate) => extractDescriptionValue(candidate?.properties)
|
|
1138
1466
|
);
|
|
1139
|
-
return matchWithDescription
|
|
1467
|
+
if (matchWithDescription) return getResult(matchWithDescription, "fallback>description");
|
|
1468
|
+
return getResult(candidates[0], "fallback>first");
|
|
1140
1469
|
}
|
|
1141
1470
|
function normalizeCenterTuple(center) {
|
|
1142
1471
|
if (!center) return null;
|
|
@@ -1192,7 +1521,7 @@ var ZenitMap = forwardRef(({
|
|
|
1192
1521
|
if (typeof window === "undefined") return false;
|
|
1193
1522
|
return window.matchMedia("(max-width: 768px)").matches;
|
|
1194
1523
|
});
|
|
1195
|
-
const normalizedLayers =
|
|
1524
|
+
const normalizedLayers = useMemo3(() => normalizeMapLayers(map), [map]);
|
|
1196
1525
|
useEffect5(() => {
|
|
1197
1526
|
if (typeof window === "undefined") return;
|
|
1198
1527
|
const mql = window.matchMedia("(max-width: 768px)");
|
|
@@ -1241,7 +1570,7 @@ var ZenitMap = forwardRef(({
|
|
|
1241
1570
|
mapInstance.off("popupclose", handlePopupClose);
|
|
1242
1571
|
};
|
|
1243
1572
|
}, [mapInstance]);
|
|
1244
|
-
const layerStyleIndex =
|
|
1573
|
+
const layerStyleIndex = useMemo3(() => {
|
|
1245
1574
|
const index = /* @__PURE__ */ new Map();
|
|
1246
1575
|
(map?.mapLayers ?? []).forEach((entry) => {
|
|
1247
1576
|
const layerStyle = entry.layer?.style ?? entry.mapLayer?.layer?.style ?? entry.style ?? null;
|
|
@@ -1252,7 +1581,7 @@ var ZenitMap = forwardRef(({
|
|
|
1252
1581
|
});
|
|
1253
1582
|
return index;
|
|
1254
1583
|
}, [map]);
|
|
1255
|
-
const labelKeyIndex =
|
|
1584
|
+
const labelKeyIndex = useMemo3(() => {
|
|
1256
1585
|
const index = /* @__PURE__ */ new Map();
|
|
1257
1586
|
normalizedLayers.forEach((entry) => {
|
|
1258
1587
|
const label = entry.layer?.label ?? entry.mapLayer?.label ?? entry.mapLayer.layerConfig?.label;
|
|
@@ -1262,7 +1591,7 @@ var ZenitMap = forwardRef(({
|
|
|
1262
1591
|
});
|
|
1263
1592
|
return index;
|
|
1264
1593
|
}, [normalizedLayers]);
|
|
1265
|
-
const layerMetaIndex =
|
|
1594
|
+
const layerMetaIndex = useMemo3(() => {
|
|
1266
1595
|
const index = /* @__PURE__ */ new Map();
|
|
1267
1596
|
normalizedLayers.forEach((entry) => {
|
|
1268
1597
|
index.set(String(entry.layerId), {
|
|
@@ -1272,7 +1601,7 @@ var ZenitMap = forwardRef(({
|
|
|
1272
1601
|
});
|
|
1273
1602
|
return index;
|
|
1274
1603
|
}, [normalizedLayers]);
|
|
1275
|
-
const overlayStyleFunction =
|
|
1604
|
+
const overlayStyleFunction = useMemo3(() => {
|
|
1276
1605
|
return (feature) => {
|
|
1277
1606
|
const featureLayerId = getFeatureLayerId(feature);
|
|
1278
1607
|
const featureStyleOverrides = getFeatureStyleOverrides(feature);
|
|
@@ -1456,7 +1785,7 @@ var ZenitMap = forwardRef(({
|
|
|
1456
1785
|
},
|
|
1457
1786
|
[currentZoom, effectiveStates, layerMetaIndex, layerStates, onLayerStateChange]
|
|
1458
1787
|
);
|
|
1459
|
-
const center =
|
|
1788
|
+
const center = useMemo3(() => {
|
|
1460
1789
|
if (initialCenter) {
|
|
1461
1790
|
return initialCenter;
|
|
1462
1791
|
}
|
|
@@ -1480,7 +1809,7 @@ var ZenitMap = forwardRef(({
|
|
|
1480
1809
|
}
|
|
1481
1810
|
});
|
|
1482
1811
|
}, [layerGeojson, layers]);
|
|
1483
|
-
const decoratedLayers =
|
|
1812
|
+
const decoratedLayers = useMemo3(() => {
|
|
1484
1813
|
return layers.map((layer) => {
|
|
1485
1814
|
const layerKey = String(layer.mapLayer.layerId);
|
|
1486
1815
|
const override = layerGeojsonOverrides[layerKey];
|
|
@@ -1491,10 +1820,10 @@ var ZenitMap = forwardRef(({
|
|
|
1491
1820
|
};
|
|
1492
1821
|
});
|
|
1493
1822
|
}, [effectiveStates, layerGeojson, layerGeojsonOverrides, layers]);
|
|
1494
|
-
const orderedLayers =
|
|
1823
|
+
const orderedLayers = useMemo3(() => {
|
|
1495
1824
|
return [...decoratedLayers].filter((layer) => layer.effective?.visible && layer.data).sort((a, b) => a.displayOrder - b.displayOrder);
|
|
1496
1825
|
}, [decoratedLayers]);
|
|
1497
|
-
const autoZoomGeojson =
|
|
1826
|
+
const autoZoomGeojson = useMemo3(
|
|
1498
1827
|
() => orderedLayers.map((layer) => layer.data).filter((collection) => !!collection),
|
|
1499
1828
|
[orderedLayers]
|
|
1500
1829
|
);
|
|
@@ -1504,7 +1833,7 @@ var ZenitMap = forwardRef(({
|
|
|
1504
1833
|
},
|
|
1505
1834
|
[layerStyleIndex, mapLayers]
|
|
1506
1835
|
);
|
|
1507
|
-
const labelMarkers =
|
|
1836
|
+
const labelMarkers = useMemo3(() => {
|
|
1508
1837
|
const markers = [];
|
|
1509
1838
|
decoratedLayers.forEach((layerState) => {
|
|
1510
1839
|
if (!layerState.effective?.visible) return;
|
|
@@ -1543,7 +1872,8 @@ var ZenitMap = forwardRef(({
|
|
|
1543
1872
|
}, [currentZoom, decoratedLayers, labelKeyIndex, layerMetaIndex, resolveLayerStyle]);
|
|
1544
1873
|
const ensureLayerPanes = useCallback2(
|
|
1545
1874
|
(targetMap, targetLayers) => {
|
|
1546
|
-
const
|
|
1875
|
+
const fillBaseZIndex = 400;
|
|
1876
|
+
const pointsBaseZIndex = 700;
|
|
1547
1877
|
targetLayers.forEach((layer) => {
|
|
1548
1878
|
const order = Number.isFinite(layer.displayOrder) ? layer.displayOrder : 0;
|
|
1549
1879
|
const orderOffset = Math.max(0, Math.min(order, 150));
|
|
@@ -1551,8 +1881,8 @@ var ZenitMap = forwardRef(({
|
|
|
1551
1881
|
const pointPaneName = `zenit-layer-${layer.layerId}-points`;
|
|
1552
1882
|
const fillPane = targetMap.getPane(fillPaneName) ?? targetMap.createPane(fillPaneName);
|
|
1553
1883
|
const pointPane = targetMap.getPane(pointPaneName) ?? targetMap.createPane(pointPaneName);
|
|
1554
|
-
fillPane.style.zIndex = String(
|
|
1555
|
-
pointPane.style.zIndex = String(
|
|
1884
|
+
fillPane.style.zIndex = String(fillBaseZIndex + orderOffset);
|
|
1885
|
+
pointPane.style.zIndex = String(pointsBaseZIndex + orderOffset);
|
|
1556
1886
|
});
|
|
1557
1887
|
},
|
|
1558
1888
|
[]
|
|
@@ -1570,114 +1900,149 @@ var ZenitMap = forwardRef(({
|
|
|
1570
1900
|
setPanesReady(false);
|
|
1571
1901
|
return;
|
|
1572
1902
|
}
|
|
1573
|
-
if (orderedLayers.length === 0) {
|
|
1903
|
+
if (orderedLayers.length === 0 && !overlayGeojson) {
|
|
1574
1904
|
return;
|
|
1575
1905
|
}
|
|
1576
1906
|
const layerTargets = orderedLayers.map((layer) => ({
|
|
1577
1907
|
layerId: layer.mapLayer.layerId,
|
|
1578
1908
|
displayOrder: layer.displayOrder
|
|
1579
1909
|
}));
|
|
1910
|
+
if (overlayGeojson) {
|
|
1911
|
+
layerTargets.push({ layerId: "overlay-geojson", displayOrder: 999 });
|
|
1912
|
+
}
|
|
1580
1913
|
ensureLayerPanes(mapInstance, layerTargets);
|
|
1581
1914
|
const first = layerTargets[0];
|
|
1582
|
-
const testPane = mapInstance.getPane(`zenit-layer-${first.layerId}-fill`);
|
|
1915
|
+
const testPane = first ? mapInstance.getPane(`zenit-layer-${first.layerId}-fill`) : null;
|
|
1583
1916
|
const labelsPane = mapInstance.getPane(LABELS_PANE_NAME);
|
|
1584
1917
|
if (testPane && labelsPane) {
|
|
1585
1918
|
setPanesReady(true);
|
|
1586
1919
|
}
|
|
1587
|
-
}, [mapInstance, orderedLayers, ensureLayerPanes]);
|
|
1588
|
-
const overlayOnEachFeature =
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
if (isPointFeature && layer.bindTooltip) {
|
|
1617
|
-
layer.bindTooltip("Click para ver detalle", {
|
|
1618
|
-
sticky: true,
|
|
1619
|
-
direction: "top",
|
|
1620
|
-
opacity: 0.9,
|
|
1621
|
-
className: "zenit-map-tooltip"
|
|
1920
|
+
}, [mapInstance, orderedLayers, overlayGeojson, ensureLayerPanes]);
|
|
1921
|
+
const overlayOnEachFeature = useCallback2((feature, layer) => {
|
|
1922
|
+
const layerId = getFeatureLayerId(feature) ?? void 0;
|
|
1923
|
+
const geometryType = feature?.geometry?.type;
|
|
1924
|
+
const clickIntent = getClickIntent({ feature, leafletLayer: layer });
|
|
1925
|
+
const isPointFeature = clickIntent === "point";
|
|
1926
|
+
const originalStyle = layer instanceof L4.Path ? {
|
|
1927
|
+
color: layer.options.color,
|
|
1928
|
+
weight: layer.options.weight,
|
|
1929
|
+
fillColor: layer.options.fillColor,
|
|
1930
|
+
opacity: layer.options.opacity,
|
|
1931
|
+
fillOpacity: layer.options.fillOpacity
|
|
1932
|
+
} : null;
|
|
1933
|
+
const originalRadius = layer instanceof L4.CircleMarker ? layer.getRadius() : null;
|
|
1934
|
+
if (featureInfoMode === "popup") {
|
|
1935
|
+
const content = buildFeaturePopupHtml(feature);
|
|
1936
|
+
if (content) {
|
|
1937
|
+
const { maxWidth, minWidth, maxHeight } = getPopupDimensions();
|
|
1938
|
+
layer.bindPopup(content, {
|
|
1939
|
+
maxWidth,
|
|
1940
|
+
minWidth,
|
|
1941
|
+
maxHeight,
|
|
1942
|
+
className: "custom-leaflet-popup",
|
|
1943
|
+
autoClose: true,
|
|
1944
|
+
closeOnClick: true,
|
|
1945
|
+
autoPan: true,
|
|
1946
|
+
closeButton: true,
|
|
1947
|
+
keepInView: true,
|
|
1948
|
+
autoPanPadding: [50, 50]
|
|
1622
1949
|
});
|
|
1623
1950
|
}
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
geometry: feature.geometry
|
|
1632
|
-
}).then((response) => {
|
|
1633
|
-
const geo = extractGeoJsonFeatureCollection(response);
|
|
1634
|
-
const candidates = geo?.features ?? [];
|
|
1635
|
-
const resolved = pickIntersectFeature(feature, candidates);
|
|
1636
|
-
if (!resolved?.properties) return;
|
|
1637
|
-
const mergedProperties = {
|
|
1638
|
-
...trackedFeature.properties ?? {},
|
|
1639
|
-
...resolved.properties
|
|
1640
|
-
};
|
|
1641
|
-
trackedFeature.properties = mergedProperties;
|
|
1642
|
-
const updatedHtml = buildFeaturePopupHtml({
|
|
1643
|
-
...feature,
|
|
1644
|
-
properties: mergedProperties
|
|
1645
|
-
});
|
|
1646
|
-
if (updatedHtml && layer.setPopupContent) {
|
|
1647
|
-
layer.setPopupContent(updatedHtml);
|
|
1648
|
-
}
|
|
1649
|
-
}).catch(() => {
|
|
1650
|
-
trackedFeature.__zenit_popup_loaded = false;
|
|
1651
|
-
});
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
|
-
onFeatureClick?.(feature, layerId);
|
|
1951
|
+
}
|
|
1952
|
+
if (isPointFeature && layer.bindTooltip) {
|
|
1953
|
+
layer.bindTooltip("Click para ver detalle", {
|
|
1954
|
+
sticky: true,
|
|
1955
|
+
direction: "top",
|
|
1956
|
+
opacity: 0.9,
|
|
1957
|
+
className: "zenit-map-tooltip"
|
|
1655
1958
|
});
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1959
|
+
}
|
|
1960
|
+
layer.on("click", () => {
|
|
1961
|
+
if (featureInfoMode === "popup" && client && layerId !== void 0 && !extractDescriptionValue(feature?.properties) && feature?.geometry) {
|
|
1962
|
+
if (DEV_MODE2) {
|
|
1963
|
+
console.debug("[ZenitMap] click/intersect:start", {
|
|
1964
|
+
expectedLayerId: layerId,
|
|
1965
|
+
geometryType,
|
|
1966
|
+
clickIntent,
|
|
1967
|
+
leafletLayerType: layer?.constructor?.name,
|
|
1968
|
+
pane: layer?.options?.pane
|
|
1663
1969
|
});
|
|
1664
1970
|
}
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1971
|
+
const trackedFeature = feature;
|
|
1972
|
+
if (!trackedFeature.__zenit_popup_loaded) {
|
|
1973
|
+
trackedFeature.__zenit_popup_loaded = true;
|
|
1974
|
+
client.layers.getLayerGeoJsonIntersect({
|
|
1975
|
+
id: layerId,
|
|
1976
|
+
geometry: feature.geometry
|
|
1977
|
+
}).then((response) => {
|
|
1978
|
+
const geo = extractGeoJsonFeatureCollection(response);
|
|
1979
|
+
const candidates = geo?.features ?? [];
|
|
1980
|
+
const selection = pickIntersectFeature({
|
|
1981
|
+
baseFeature: feature,
|
|
1982
|
+
candidates,
|
|
1983
|
+
expectedLayerId: layerId,
|
|
1984
|
+
clickIntent
|
|
1985
|
+
});
|
|
1986
|
+
const resolved = selection?.feature;
|
|
1987
|
+
if (DEV_MODE2) {
|
|
1988
|
+
console.debug("[ZenitMap] click/intersect:result", {
|
|
1989
|
+
expectedLayerId: layerId,
|
|
1990
|
+
clickIntent,
|
|
1991
|
+
candidatesCount: candidates.length,
|
|
1992
|
+
candidates: candidates.map((candidate, idx) => ({
|
|
1993
|
+
idx,
|
|
1994
|
+
geomType: candidate?.geometry?.type,
|
|
1995
|
+
candidateLayerId: candidateLayerId(candidate),
|
|
1996
|
+
hasDescription: Boolean(extractDescriptionValue(candidate?.properties))
|
|
1997
|
+
})),
|
|
1998
|
+
selectedIdx: selection?.selectedIdx ?? -1,
|
|
1999
|
+
selectionRule: selection?.reason ?? "none"
|
|
2000
|
+
});
|
|
2001
|
+
}
|
|
2002
|
+
if (!resolved?.properties) return;
|
|
2003
|
+
const mergedProperties = {
|
|
2004
|
+
...trackedFeature.properties ?? {},
|
|
2005
|
+
...resolved.properties
|
|
2006
|
+
};
|
|
2007
|
+
trackedFeature.properties = mergedProperties;
|
|
2008
|
+
const updatedHtml = buildFeaturePopupHtml({
|
|
2009
|
+
...feature,
|
|
2010
|
+
properties: mergedProperties
|
|
2011
|
+
});
|
|
2012
|
+
if (updatedHtml && layer.setPopupContent) {
|
|
2013
|
+
layer.setPopupContent(updatedHtml);
|
|
2014
|
+
}
|
|
2015
|
+
}).catch(() => {
|
|
2016
|
+
trackedFeature.__zenit_popup_loaded = false;
|
|
2017
|
+
});
|
|
1676
2018
|
}
|
|
1677
|
-
}
|
|
1678
|
-
|
|
2019
|
+
}
|
|
2020
|
+
onFeatureClick?.(feature, layerId);
|
|
2021
|
+
});
|
|
2022
|
+
layer.on("mouseover", () => {
|
|
2023
|
+
if (layer instanceof L4.Path && originalStyle) {
|
|
2024
|
+
layer.setStyle({
|
|
2025
|
+
...originalStyle,
|
|
2026
|
+
weight: (originalStyle.weight ?? 2) + 1,
|
|
2027
|
+
opacity: Math.min(1, (originalStyle.opacity ?? 1) + 0.2),
|
|
2028
|
+
fillOpacity: Math.min(1, (originalStyle.fillOpacity ?? 0.8) + 0.1)
|
|
2029
|
+
});
|
|
2030
|
+
}
|
|
2031
|
+
if (layer instanceof L4.CircleMarker && typeof originalRadius === "number") {
|
|
2032
|
+
layer.setRadius(originalRadius + 1);
|
|
2033
|
+
}
|
|
2034
|
+
onFeatureHover?.(feature, layerId);
|
|
2035
|
+
});
|
|
2036
|
+
layer.on("mouseout", () => {
|
|
2037
|
+
if (layer instanceof L4.Path && originalStyle) {
|
|
2038
|
+
layer.setStyle(originalStyle);
|
|
2039
|
+
}
|
|
2040
|
+
if (layer instanceof L4.CircleMarker && typeof originalRadius === "number") {
|
|
2041
|
+
layer.setRadius(originalRadius);
|
|
2042
|
+
}
|
|
2043
|
+
});
|
|
1679
2044
|
}, [client, featureInfoMode, onFeatureClick, onFeatureHover]);
|
|
1680
|
-
const buildLayerStyle = (layerId, baseOpacity, feature, layerType) => {
|
|
2045
|
+
const buildLayerStyle = useCallback2((layerId, baseOpacity, feature, layerType) => {
|
|
1681
2046
|
const style = resolveLayerStyle(layerId);
|
|
1682
2047
|
const featureStyleOverrides = getFeatureStyleOverrides(feature);
|
|
1683
2048
|
const resolvedStyle = featureStyleOverrides ? { ...style ?? {}, ...featureStyleOverrides } : style;
|
|
@@ -1688,14 +2053,15 @@ var ZenitMap = forwardRef(({
|
|
|
1688
2053
|
zoom: currentZoom,
|
|
1689
2054
|
layerStyle: resolvedStyle,
|
|
1690
2055
|
geometryType,
|
|
1691
|
-
layerType: resolvedLayerType
|
|
2056
|
+
layerType: resolvedLayerType,
|
|
2057
|
+
properties: feature?.properties ?? void 0
|
|
1692
2058
|
});
|
|
1693
|
-
};
|
|
1694
|
-
const makeStyleFnForLayer = (layerId) => {
|
|
2059
|
+
}, [currentZoom, resolveLayerStyle]);
|
|
2060
|
+
const makeStyleFnForLayer = useCallback2((layerId) => {
|
|
1695
2061
|
return (feature, layerType, baseOpacity) => {
|
|
1696
2062
|
return buildLayerStyle(layerId, baseOpacity ?? 1, feature, layerType);
|
|
1697
2063
|
};
|
|
1698
|
-
};
|
|
2064
|
+
}, [buildLayerStyle]);
|
|
1699
2065
|
useImperativeHandle(ref, () => ({
|
|
1700
2066
|
setLayerOpacity: (layerId, opacity) => {
|
|
1701
2067
|
upsertUiOverride(layerId, { overrideOpacity: opacity });
|
|
@@ -1850,7 +2216,7 @@ var ZenitMap = forwardRef(({
|
|
|
1850
2216
|
const layerType = layerState.layer?.layerType ?? layerState.mapLayer.layerType ?? void 0;
|
|
1851
2217
|
const labelKey = labelKeyIndex.get(String(layerState.mapLayer.layerId));
|
|
1852
2218
|
return /* @__PURE__ */ jsxs3(React4.Fragment, { children: [
|
|
1853
|
-
layerState.data && /* @__PURE__ */ jsx3(
|
|
2219
|
+
layerState.data && panesReady && /* @__PURE__ */ jsx3(
|
|
1854
2220
|
LayerGeoJson,
|
|
1855
2221
|
{
|
|
1856
2222
|
layerId: layerState.mapLayer.layerId,
|
|
@@ -1893,7 +2259,7 @@ var ZenitMap = forwardRef(({
|
|
|
1893
2259
|
)) : null
|
|
1894
2260
|
] }, layerState.mapLayer.layerId.toString());
|
|
1895
2261
|
}),
|
|
1896
|
-
overlayGeojson && /* @__PURE__ */ jsx3(
|
|
2262
|
+
overlayGeojson && panesReady && /* @__PURE__ */ jsx3(
|
|
1897
2263
|
LayerGeoJson,
|
|
1898
2264
|
{
|
|
1899
2265
|
layerId: "overlay-geojson",
|
|
@@ -1927,7 +2293,7 @@ var ZenitMap = forwardRef(({
|
|
|
1927
2293
|
overflowY: "auto"
|
|
1928
2294
|
},
|
|
1929
2295
|
children: [
|
|
1930
|
-
overlayGeojson && /* @__PURE__ */ jsxs3(
|
|
2296
|
+
overlayGeojson && panesReady && /* @__PURE__ */ jsxs3(
|
|
1931
2297
|
"div",
|
|
1932
2298
|
{
|
|
1933
2299
|
style: {
|
|
@@ -2006,7 +2372,7 @@ var ZenitMap = forwardRef(({
|
|
|
2006
2372
|
ZenitMap.displayName = "ZenitMap";
|
|
2007
2373
|
|
|
2008
2374
|
// src/react/ZenitLayerManager.tsx
|
|
2009
|
-
import React6, { useEffect as useEffect6, useMemo as
|
|
2375
|
+
import React6, { useEffect as useEffect6, useMemo as useMemo4, useRef as useRef6, useState as useState3 } from "react";
|
|
2010
2376
|
|
|
2011
2377
|
// src/react/icons.tsx
|
|
2012
2378
|
import { Eye, EyeOff, ChevronDown, ChevronLeft, ChevronRight, Layers, Upload, X, ZoomIn } from "lucide-react";
|
|
@@ -2424,7 +2790,7 @@ var ZenitLayerManager = ({
|
|
|
2424
2790
|
const catalogAbortRef = useRef6(null);
|
|
2425
2791
|
const lastEmittedStatesRef = useRef6(null);
|
|
2426
2792
|
const isControlled = Array.isArray(layerStates) && typeof onLayerStatesChange === "function";
|
|
2427
|
-
const baseStates =
|
|
2793
|
+
const baseStates = useMemo4(
|
|
2428
2794
|
() => initLayerStates(
|
|
2429
2795
|
layers.map((entry) => ({
|
|
2430
2796
|
...entry.mapLayer,
|
|
@@ -2435,7 +2801,7 @@ var ZenitLayerManager = ({
|
|
|
2435
2801
|
),
|
|
2436
2802
|
[layers]
|
|
2437
2803
|
);
|
|
2438
|
-
const overrideStates =
|
|
2804
|
+
const overrideStates = useMemo4(
|
|
2439
2805
|
() => layers.map(
|
|
2440
2806
|
(entry) => ({
|
|
2441
2807
|
layerId: entry.mapLayer.layerId,
|
|
@@ -2445,11 +2811,11 @@ var ZenitLayerManager = ({
|
|
|
2445
2811
|
),
|
|
2446
2812
|
[layers]
|
|
2447
2813
|
);
|
|
2448
|
-
const effectiveStates =
|
|
2814
|
+
const effectiveStates = useMemo4(
|
|
2449
2815
|
() => layerStates ?? applyLayerOverrides(baseStates, overrideStates),
|
|
2450
2816
|
[baseStates, layerStates, overrideStates]
|
|
2451
2817
|
);
|
|
2452
|
-
const layerMetaIndex =
|
|
2818
|
+
const layerMetaIndex = useMemo4(() => {
|
|
2453
2819
|
const index = /* @__PURE__ */ new Map();
|
|
2454
2820
|
mapLayers?.forEach((entry) => {
|
|
2455
2821
|
const key = String(entry.layerId);
|
|
@@ -2487,7 +2853,7 @@ var ZenitLayerManager = ({
|
|
|
2487
2853
|
},
|
|
2488
2854
|
[autoOpacityConfig, autoOpacityOnZoom, layerMetaIndex, mapZoom]
|
|
2489
2855
|
);
|
|
2490
|
-
const effectiveStatesWithZoom =
|
|
2856
|
+
const effectiveStatesWithZoom = useMemo4(() => {
|
|
2491
2857
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
2492
2858
|
return effectiveStates;
|
|
2493
2859
|
}
|
|
@@ -2586,7 +2952,7 @@ var ZenitLayerManager = ({
|
|
|
2586
2952
|
},
|
|
2587
2953
|
[layerFeatureCounts]
|
|
2588
2954
|
);
|
|
2589
|
-
const decoratedLayers =
|
|
2955
|
+
const decoratedLayers = useMemo4(() => {
|
|
2590
2956
|
return layers.map((entry) => ({
|
|
2591
2957
|
...entry,
|
|
2592
2958
|
effective: effectiveStates.find((state) => state.layerId === entry.mapLayer.layerId),
|
|
@@ -2615,17 +2981,25 @@ var ZenitLayerManager = ({
|
|
|
2615
2981
|
return String(a.mapLayer.layerId).localeCompare(String(b.mapLayer.layerId));
|
|
2616
2982
|
});
|
|
2617
2983
|
}, [effectiveStates, layers, resolveFeatureCount]);
|
|
2618
|
-
const
|
|
2984
|
+
const hasPrefilters = useMemo4(() => {
|
|
2985
|
+
const candidates = [...mapLayers ?? [], ...map?.mapLayers ?? []];
|
|
2986
|
+
return candidates.some((layer) => {
|
|
2987
|
+
const record = layer;
|
|
2988
|
+
const applied = record.appliedFilters ?? record.prefilters ?? record.initialFilters ?? record.filters ?? (record.layerConfig?.appliedFilters ?? record.layerConfig?.prefilters);
|
|
2989
|
+
return !!applied && typeof applied === "object" && Object.keys(applied).length > 0;
|
|
2990
|
+
});
|
|
2991
|
+
}, [map?.mapLayers, mapLayers]);
|
|
2992
|
+
const filterableLayers = useMemo4(() => {
|
|
2619
2993
|
return decoratedLayers.filter((entry) => {
|
|
2620
2994
|
const prefilters = entry.mapLayer.layerConfig?.prefilters;
|
|
2621
2995
|
return !!prefilters && Object.keys(prefilters).length > 0;
|
|
2622
2996
|
});
|
|
2623
2997
|
}, [decoratedLayers]);
|
|
2624
|
-
const selectedFilterLayer =
|
|
2998
|
+
const selectedFilterLayer = useMemo4(
|
|
2625
2999
|
() => filterableLayers.find((layer) => String(layer.mapLayer.layerId) === selectedFilterLayerId) ?? null,
|
|
2626
3000
|
[filterableLayers, selectedFilterLayerId]
|
|
2627
3001
|
);
|
|
2628
|
-
const filterFields =
|
|
3002
|
+
const filterFields = useMemo4(() => {
|
|
2629
3003
|
const prefilters = selectedFilterLayer?.mapLayer.layerConfig?.prefilters;
|
|
2630
3004
|
return prefilters ? Object.keys(prefilters) : [];
|
|
2631
3005
|
}, [selectedFilterLayer]);
|
|
@@ -2687,6 +3061,11 @@ var ZenitLayerManager = ({
|
|
|
2687
3061
|
setSelectedFilterValue("");
|
|
2688
3062
|
}
|
|
2689
3063
|
}, [filterFields, selectedFilterField]);
|
|
3064
|
+
useEffect6(() => {
|
|
3065
|
+
if (hasPrefilters && activeTab === "filters") {
|
|
3066
|
+
setActiveTab("layers");
|
|
3067
|
+
}
|
|
3068
|
+
}, [activeTab, hasPrefilters]);
|
|
2690
3069
|
useEffect6(() => {
|
|
2691
3070
|
if (activeTab !== "filters") return;
|
|
2692
3071
|
if (!selectedFilterLayer || !selectedFilterField || !activeCatalogKey) return;
|
|
@@ -3087,7 +3466,7 @@ var ZenitLayerManager = ({
|
|
|
3087
3466
|
]
|
|
3088
3467
|
}
|
|
3089
3468
|
),
|
|
3090
|
-
/* @__PURE__ */ jsxs5(
|
|
3469
|
+
!hasPrefilters && /* @__PURE__ */ jsxs5(
|
|
3091
3470
|
"button",
|
|
3092
3471
|
{
|
|
3093
3472
|
type: "button",
|
|
@@ -3104,8 +3483,9 @@ var ZenitLayerManager = ({
|
|
|
3104
3483
|
)
|
|
3105
3484
|
] }),
|
|
3106
3485
|
panelVisible && /* @__PURE__ */ jsxs5("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
|
|
3486
|
+
hasPrefilters && /* @__PURE__ */ jsx5("div", { className: "zlm-badge", style: { marginBottom: 10 }, children: "Este mapa ya incluye filtros preaplicados" }),
|
|
3107
3487
|
activeTab === "layers" && renderLayerCards(),
|
|
3108
|
-
activeTab === "filters" && /* @__PURE__ */ jsx5("div", { className: "zlm-filter-panel", style: { display: "flex", flexDirection: "column", gap: 12, background: "#fff", border: "1px solid #e2e8f0", borderRadius: 12, padding: 12 }, children: !filterableLayers.length ? /* @__PURE__ */ jsx5("div", { style: { color: "#64748b", fontSize: 13 }, children: "No hay filtros disponibles para las capas de este mapa." }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3488
|
+
!hasPrefilters && activeTab === "filters" && /* @__PURE__ */ jsx5("div", { className: "zlm-filter-panel", style: { display: "flex", flexDirection: "column", gap: 12, background: "#fff", border: "1px solid #e2e8f0", borderRadius: 12, padding: 12 }, children: !filterableLayers.length ? /* @__PURE__ */ jsx5("div", { style: { color: "#64748b", fontSize: 13 }, children: "No hay filtros disponibles para las capas de este mapa." }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3109
3489
|
filterableLayers.length > 1 && /* @__PURE__ */ jsxs5("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
|
|
3110
3490
|
"Capa",
|
|
3111
3491
|
/* @__PURE__ */ jsx5(
|
|
@@ -3223,7 +3603,7 @@ var ZenitFeatureFilterPanel = ({
|
|
|
3223
3603
|
};
|
|
3224
3604
|
|
|
3225
3605
|
// src/react/ai/FloatingChatBox.tsx
|
|
3226
|
-
import { useCallback as useCallback4, useEffect as useEffect7, useMemo as
|
|
3606
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useMemo as useMemo5, useRef as useRef8, useState as useState5 } from "react";
|
|
3227
3607
|
import { createPortal as createPortal3 } from "react-dom";
|
|
3228
3608
|
|
|
3229
3609
|
// src/react/hooks/use-chat.ts
|
|
@@ -3948,7 +4328,7 @@ var FloatingChatBox = ({
|
|
|
3948
4328
|
const messagesEndRef = useRef8(null);
|
|
3949
4329
|
const messagesContainerRef = useRef8(null);
|
|
3950
4330
|
const chatBoxRef = useRef8(null);
|
|
3951
|
-
const chatConfig =
|
|
4331
|
+
const chatConfig = useMemo5(() => {
|
|
3952
4332
|
if (!baseUrl) return void 0;
|
|
3953
4333
|
return { baseUrl, accessToken, getAccessToken };
|
|
3954
4334
|
}, [accessToken, baseUrl, getAccessToken]);
|
|
@@ -4447,4 +4827,4 @@ export {
|
|
|
4447
4827
|
useSendMessageStream,
|
|
4448
4828
|
FloatingChatBox
|
|
4449
4829
|
};
|
|
4450
|
-
//# sourceMappingURL=chunk-
|
|
4830
|
+
//# sourceMappingURL=chunk-J2YWF2TS.mjs.map
|