zenit-sdk 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-PCTRVN4O.mjs → chunk-URDEEWUZ.mjs} +446 -94
- package/dist/chunk-URDEEWUZ.mjs.map +1 -0
- package/dist/{index-DvcYGhqj.d.mts → index-BSljZaYk.d.mts} +13 -0
- package/dist/{index-DvcYGhqj.d.ts → index-BSljZaYk.d.ts} +13 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +527 -170
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10 -5
- 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 +518 -166
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-PCTRVN4O.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -371,10 +371,6 @@ function parseQueryParams(options = {}) {
|
|
|
371
371
|
return params;
|
|
372
372
|
}
|
|
373
373
|
function serializeFilterValue(value) {
|
|
374
|
-
if (Array.isArray(value)) {
|
|
375
|
-
const serialized2 = value.map(String).filter((item) => item.trim().length > 0).join(",");
|
|
376
|
-
return serialized2.length > 0 ? serialized2 : void 0;
|
|
377
|
-
}
|
|
378
374
|
if (value === void 0 || value === null) {
|
|
379
375
|
return void 0;
|
|
380
376
|
}
|
|
@@ -387,6 +383,15 @@ function buildLayerFilters(filters) {
|
|
|
387
383
|
return query;
|
|
388
384
|
}
|
|
389
385
|
Object.entries(filters).forEach(([key, value]) => {
|
|
386
|
+
if (Array.isArray(value)) {
|
|
387
|
+
value.forEach((item) => {
|
|
388
|
+
const serialized2 = serializeFilterValue(item);
|
|
389
|
+
if (serialized2 !== void 0) {
|
|
390
|
+
query.append(key, serialized2);
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
390
395
|
const serialized = serializeFilterValue(value);
|
|
391
396
|
if (serialized !== void 0) {
|
|
392
397
|
query.set(key, serialized);
|
|
@@ -1521,7 +1526,7 @@ function normalizeBbox(input) {
|
|
|
1521
1526
|
}
|
|
1522
1527
|
|
|
1523
1528
|
// src/react/ZenitMap.tsx
|
|
1524
|
-
var
|
|
1529
|
+
var import_react5 = __toESM(require("react"));
|
|
1525
1530
|
var import_react_leaflet4 = require("react-leaflet");
|
|
1526
1531
|
var import_leaflet4 = __toESM(require("leaflet"));
|
|
1527
1532
|
|
|
@@ -1585,10 +1590,31 @@ function getEffectiveLayerOpacity(baseOpacity, zoom, layerType, geometryType, op
|
|
|
1585
1590
|
}
|
|
1586
1591
|
|
|
1587
1592
|
// src/react/map/layer-geojson.tsx
|
|
1593
|
+
var import_react = require("react");
|
|
1588
1594
|
var import_react_leaflet = require("react-leaflet");
|
|
1589
1595
|
var import_leaflet = __toESM(require("leaflet"));
|
|
1590
1596
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1591
1597
|
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
1598
|
+
function normalizeBboxFromData(data) {
|
|
1599
|
+
const bboxCandidate = data.bbox;
|
|
1600
|
+
if (!Array.isArray(bboxCandidate) || bboxCandidate.length < 4) return null;
|
|
1601
|
+
const [minLon, minLat, maxLon, maxLat] = bboxCandidate;
|
|
1602
|
+
const values = [minLon, minLat, maxLon, maxLat].map((value) => Number(value));
|
|
1603
|
+
if (values.every((value) => Number.isFinite(value))) {
|
|
1604
|
+
return values;
|
|
1605
|
+
}
|
|
1606
|
+
return null;
|
|
1607
|
+
}
|
|
1608
|
+
function buildIdsSample(features) {
|
|
1609
|
+
return features.slice(0, 10).map((feature) => {
|
|
1610
|
+
const typedFeature = feature;
|
|
1611
|
+
if (typedFeature.id !== void 0 && typedFeature.id !== null) {
|
|
1612
|
+
return String(typedFeature.id);
|
|
1613
|
+
}
|
|
1614
|
+
const featureId = typedFeature.properties?.featureId;
|
|
1615
|
+
return featureId !== void 0 && featureId !== null ? String(featureId) : "";
|
|
1616
|
+
}).join(",");
|
|
1617
|
+
}
|
|
1592
1618
|
function getGeometryType(feature) {
|
|
1593
1619
|
const t = feature?.geometry?.type;
|
|
1594
1620
|
return typeof t === "string" ? t : null;
|
|
@@ -1624,8 +1650,58 @@ var LayerGeoJson = ({
|
|
|
1624
1650
|
const features = data.features ?? [];
|
|
1625
1651
|
const fillFeatures = features.filter(isNonPointGeometry);
|
|
1626
1652
|
const pointFeatures = features.filter(isPointGeometry);
|
|
1653
|
+
const dataVersionRef = (0, import_react.useRef)(0);
|
|
1654
|
+
const prevSignatureRef = (0, import_react.useRef)("");
|
|
1655
|
+
const firstId = features.length > 0 ? String(features[0]?.id ?? "") : "";
|
|
1656
|
+
const lastId = features.length > 0 ? String(features[features.length - 1]?.id ?? "") : "";
|
|
1657
|
+
const bbox = normalizeBboxFromData(data);
|
|
1658
|
+
const idsSample = buildIdsSample(features);
|
|
1659
|
+
const signature = bbox ? `${layerId}|${features.length}|${firstId}|${lastId}|${idsSample}|${bbox[0]}|${bbox[1]}|${bbox[2]}|${bbox[3]}` : `${layerId}|${features.length}|${firstId}|${lastId}|${idsSample}`;
|
|
1660
|
+
const signatureToken = signature.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1661
|
+
if (prevSignatureRef.current !== signature) {
|
|
1662
|
+
dataVersionRef.current += 1;
|
|
1663
|
+
prevSignatureRef.current = signature;
|
|
1664
|
+
}
|
|
1627
1665
|
const fillData = fillFeatures.length > 0 ? buildFeatureCollection(fillFeatures) : null;
|
|
1628
1666
|
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
1667
|
+
const clusterLayerRef = (0, import_react.useRef)(null);
|
|
1668
|
+
const canCluster = typeof import_leaflet.default.markerClusterGroup === "function";
|
|
1669
|
+
(0, import_react.useEffect)(() => {
|
|
1670
|
+
if (!mapInstance || !panesReady || !pointsData || !canCluster) return;
|
|
1671
|
+
const markerClusterGroup = import_leaflet.default.markerClusterGroup;
|
|
1672
|
+
const clusterLayer = clusterLayerRef.current ?? markerClusterGroup();
|
|
1673
|
+
clusterLayerRef.current = clusterLayer;
|
|
1674
|
+
if (!mapInstance.hasLayer(clusterLayer)) {
|
|
1675
|
+
mapInstance.addLayer(clusterLayer);
|
|
1676
|
+
}
|
|
1677
|
+
clusterLayer.clearLayers();
|
|
1678
|
+
const geoJsonLayer = import_leaflet.default.geoJSON(pointsData, {
|
|
1679
|
+
pointToLayer: (feature, latlng) => import_leaflet.default.circleMarker(latlng, {
|
|
1680
|
+
radius: isMobile ? 8 : 6,
|
|
1681
|
+
pane: mapInstance.getPane(pointsPaneName) ? pointsPaneName : void 0,
|
|
1682
|
+
...styleFn(feature, layerType, baseOpacity)
|
|
1683
|
+
}),
|
|
1684
|
+
onEachFeature
|
|
1685
|
+
});
|
|
1686
|
+
clusterLayer.addLayer(geoJsonLayer);
|
|
1687
|
+
return () => {
|
|
1688
|
+
clusterLayer.clearLayers();
|
|
1689
|
+
if (mapInstance.hasLayer(clusterLayer)) {
|
|
1690
|
+
mapInstance.removeLayer(clusterLayer);
|
|
1691
|
+
}
|
|
1692
|
+
};
|
|
1693
|
+
}, [
|
|
1694
|
+
baseOpacity,
|
|
1695
|
+
canCluster,
|
|
1696
|
+
isMobile,
|
|
1697
|
+
layerType,
|
|
1698
|
+
mapInstance,
|
|
1699
|
+
onEachFeature,
|
|
1700
|
+
panesReady,
|
|
1701
|
+
pointsData,
|
|
1702
|
+
pointsPaneName,
|
|
1703
|
+
styleFn
|
|
1704
|
+
]);
|
|
1629
1705
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1630
1706
|
fillData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1631
1707
|
import_react_leaflet.GeoJSON,
|
|
@@ -1638,9 +1714,9 @@ var LayerGeoJson = ({
|
|
|
1638
1714
|
onPolygonLabel?.(feature, layer);
|
|
1639
1715
|
}
|
|
1640
1716
|
},
|
|
1641
|
-
`fill-${layerId}`
|
|
1717
|
+
`fill-${layerId}-${signatureToken}-v${dataVersionRef.current}`
|
|
1642
1718
|
),
|
|
1643
|
-
pointsData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1719
|
+
pointsData && !canCluster && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1644
1720
|
import_react_leaflet.GeoJSON,
|
|
1645
1721
|
{
|
|
1646
1722
|
data: pointsData,
|
|
@@ -1651,32 +1727,32 @@ var LayerGeoJson = ({
|
|
|
1651
1727
|
}),
|
|
1652
1728
|
onEachFeature
|
|
1653
1729
|
},
|
|
1654
|
-
`points-${layerId}`
|
|
1730
|
+
`points-${layerId}-${signatureToken}-v${dataVersionRef.current}`
|
|
1655
1731
|
)
|
|
1656
1732
|
] });
|
|
1657
1733
|
};
|
|
1658
1734
|
|
|
1659
1735
|
// src/react/map/location-control.tsx
|
|
1660
|
-
var
|
|
1736
|
+
var import_react3 = require("react");
|
|
1661
1737
|
var import_react_dom = require("react-dom");
|
|
1662
1738
|
var import_react_leaflet2 = require("react-leaflet");
|
|
1663
1739
|
var import_leaflet3 = __toESM(require("leaflet"));
|
|
1664
1740
|
|
|
1665
1741
|
// src/react/hooks/use-geolocation.ts
|
|
1666
|
-
var
|
|
1742
|
+
var import_react2 = require("react");
|
|
1667
1743
|
function useGeolocation(options) {
|
|
1668
|
-
const [isTracking, setIsTracking] = (0,
|
|
1669
|
-
const [location, setLocation] = (0,
|
|
1670
|
-
const [error, setError] = (0,
|
|
1671
|
-
const watchIdRef = (0,
|
|
1672
|
-
const stopTracking = (0,
|
|
1744
|
+
const [isTracking, setIsTracking] = (0, import_react2.useState)(false);
|
|
1745
|
+
const [location, setLocation] = (0, import_react2.useState)(null);
|
|
1746
|
+
const [error, setError] = (0, import_react2.useState)(null);
|
|
1747
|
+
const watchIdRef = (0, import_react2.useRef)(null);
|
|
1748
|
+
const stopTracking = (0, import_react2.useCallback)(() => {
|
|
1673
1749
|
if (watchIdRef.current !== null && typeof navigator !== "undefined" && navigator.geolocation) {
|
|
1674
1750
|
navigator.geolocation.clearWatch(watchIdRef.current);
|
|
1675
1751
|
}
|
|
1676
1752
|
watchIdRef.current = null;
|
|
1677
1753
|
setIsTracking(false);
|
|
1678
1754
|
}, []);
|
|
1679
|
-
const startTracking = (0,
|
|
1755
|
+
const startTracking = (0, import_react2.useCallback)(() => {
|
|
1680
1756
|
if (typeof navigator === "undefined" || !navigator.geolocation) {
|
|
1681
1757
|
setError({ code: 0, message: "La geolocalizaci\xF3n no est\xE1 disponible en este navegador." });
|
|
1682
1758
|
return;
|
|
@@ -1702,15 +1778,15 @@ function useGeolocation(options) {
|
|
|
1702
1778
|
}
|
|
1703
1779
|
);
|
|
1704
1780
|
}, [options?.enableHighAccuracy, options?.maximumAge, options?.timeout, stopTracking]);
|
|
1705
|
-
const toggleTracking = (0,
|
|
1781
|
+
const toggleTracking = (0, import_react2.useCallback)(() => {
|
|
1706
1782
|
if (isTracking) {
|
|
1707
1783
|
stopTracking();
|
|
1708
1784
|
} else {
|
|
1709
1785
|
startTracking();
|
|
1710
1786
|
}
|
|
1711
1787
|
}, [isTracking, startTracking, stopTracking]);
|
|
1712
|
-
const clearError = (0,
|
|
1713
|
-
(0,
|
|
1788
|
+
const clearError = (0, import_react2.useCallback)(() => setError(null), []);
|
|
1789
|
+
(0, import_react2.useEffect)(() => {
|
|
1714
1790
|
return () => {
|
|
1715
1791
|
stopTracking();
|
|
1716
1792
|
};
|
|
@@ -2137,10 +2213,10 @@ var LocateIcon = () => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { wi
|
|
|
2137
2213
|
] });
|
|
2138
2214
|
var LocationControl = ({ position = "bottomleft", zoom = 16 }) => {
|
|
2139
2215
|
const map = (0, import_react_leaflet2.useMap)();
|
|
2140
|
-
const controlRef = (0,
|
|
2141
|
-
const hasCenteredRef = (0,
|
|
2216
|
+
const controlRef = (0, import_react3.useRef)(null);
|
|
2217
|
+
const hasCenteredRef = (0, import_react3.useRef)(false);
|
|
2142
2218
|
const { isTracking, location, error, toggleTracking, clearError } = useGeolocation();
|
|
2143
|
-
(0,
|
|
2219
|
+
(0, import_react3.useEffect)(() => {
|
|
2144
2220
|
if (typeof document === "undefined") return;
|
|
2145
2221
|
if (document.getElementById(LOCATION_STYLE_ID)) return;
|
|
2146
2222
|
const styleTag = document.createElement("style");
|
|
@@ -2148,7 +2224,7 @@ var LocationControl = ({ position = "bottomleft", zoom = 16 }) => {
|
|
|
2148
2224
|
styleTag.textContent = LOCATION_STYLES;
|
|
2149
2225
|
document.head.appendChild(styleTag);
|
|
2150
2226
|
}, []);
|
|
2151
|
-
(0,
|
|
2227
|
+
(0, import_react3.useEffect)(() => {
|
|
2152
2228
|
const control = import_leaflet3.default.control({ position });
|
|
2153
2229
|
control.onAdd = () => {
|
|
2154
2230
|
const container = import_leaflet3.default.DomUtil.create("div", "zenit-location-control");
|
|
@@ -2162,13 +2238,13 @@ var LocationControl = ({ position = "bottomleft", zoom = 16 }) => {
|
|
|
2162
2238
|
controlRef.current = null;
|
|
2163
2239
|
};
|
|
2164
2240
|
}, [map, position]);
|
|
2165
|
-
(0,
|
|
2241
|
+
(0, import_react3.useEffect)(() => {
|
|
2166
2242
|
if (!location || !isTracking) return;
|
|
2167
2243
|
if (hasCenteredRef.current) return;
|
|
2168
2244
|
hasCenteredRef.current = true;
|
|
2169
2245
|
map.flyTo([location.lat, location.lon], zoom, { animate: true });
|
|
2170
2246
|
}, [isTracking, location, map, zoom]);
|
|
2171
|
-
const markerIcon = (0,
|
|
2247
|
+
const markerIcon = (0, import_react3.useMemo)(() => createLocationIcon(), []);
|
|
2172
2248
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2173
2249
|
controlRef.current && (0, import_react_dom.createPortal)(
|
|
2174
2250
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
@@ -2209,8 +2285,20 @@ var LocationControl = ({ position = "bottomleft", zoom = 16 }) => {
|
|
|
2209
2285
|
};
|
|
2210
2286
|
|
|
2211
2287
|
// src/react/map/map-handlers.tsx
|
|
2212
|
-
var
|
|
2288
|
+
var import_react4 = require("react");
|
|
2213
2289
|
var import_react_leaflet3 = require("react-leaflet");
|
|
2290
|
+
var MapInvalidator = ({ trigger }) => {
|
|
2291
|
+
const map = (0, import_react_leaflet3.useMap)();
|
|
2292
|
+
const lastTrigger = (0, import_react4.useRef)(void 0);
|
|
2293
|
+
(0, import_react4.useEffect)(() => {
|
|
2294
|
+
if (lastTrigger.current === trigger) return;
|
|
2295
|
+
lastTrigger.current = trigger;
|
|
2296
|
+
requestAnimationFrame(() => {
|
|
2297
|
+
map.invalidateSize();
|
|
2298
|
+
});
|
|
2299
|
+
}, [map, trigger]);
|
|
2300
|
+
return null;
|
|
2301
|
+
};
|
|
2214
2302
|
function computeBBoxFromGeojson(geojson) {
|
|
2215
2303
|
if (!geojson || !Array.isArray(geojson.features)) return null;
|
|
2216
2304
|
const coords = [];
|
|
@@ -2257,9 +2345,9 @@ var BBoxZoomHandler = ({
|
|
|
2257
2345
|
enabled = true
|
|
2258
2346
|
}) => {
|
|
2259
2347
|
const map = (0, import_react_leaflet3.useMap)();
|
|
2260
|
-
const lastAppliedBBox = (0,
|
|
2261
|
-
const lastUserInteracted = (0,
|
|
2262
|
-
(0,
|
|
2348
|
+
const lastAppliedBBox = (0, import_react4.useRef)(null);
|
|
2349
|
+
const lastUserInteracted = (0, import_react4.useRef)(false);
|
|
2350
|
+
(0, import_react4.useEffect)(() => {
|
|
2263
2351
|
const handleInteraction = () => {
|
|
2264
2352
|
lastUserInteracted.current = true;
|
|
2265
2353
|
};
|
|
@@ -2270,7 +2358,7 @@ var BBoxZoomHandler = ({
|
|
|
2270
2358
|
map.off("zoomstart", handleInteraction);
|
|
2271
2359
|
};
|
|
2272
2360
|
}, [map]);
|
|
2273
|
-
(0,
|
|
2361
|
+
(0, import_react4.useEffect)(() => {
|
|
2274
2362
|
if (!enabled) return;
|
|
2275
2363
|
let resolvedBBox = bbox ?? null;
|
|
2276
2364
|
if (!resolvedBBox && geojson) {
|
|
@@ -2298,7 +2386,7 @@ var BBoxZoomHandler = ({
|
|
|
2298
2386
|
};
|
|
2299
2387
|
var ZoomBasedOpacityHandler = ({ onZoomChange }) => {
|
|
2300
2388
|
const map = (0, import_react_leaflet3.useMap)();
|
|
2301
|
-
(0,
|
|
2389
|
+
(0, import_react4.useEffect)(() => {
|
|
2302
2390
|
const handleZoom = () => {
|
|
2303
2391
|
onZoomChange(map.getZoom());
|
|
2304
2392
|
};
|
|
@@ -2312,7 +2400,7 @@ var ZoomBasedOpacityHandler = ({ onZoomChange }) => {
|
|
|
2312
2400
|
};
|
|
2313
2401
|
var MapInstanceBridge = ({ onReady }) => {
|
|
2314
2402
|
const map = (0, import_react_leaflet3.useMap)();
|
|
2315
|
-
(0,
|
|
2403
|
+
(0, import_react4.useEffect)(() => {
|
|
2316
2404
|
onReady(map);
|
|
2317
2405
|
}, [map, onReady]);
|
|
2318
2406
|
return null;
|
|
@@ -2408,7 +2496,7 @@ function normalizeCenterTuple(center) {
|
|
|
2408
2496
|
}
|
|
2409
2497
|
return null;
|
|
2410
2498
|
}
|
|
2411
|
-
var ZenitMap = (0,
|
|
2499
|
+
var ZenitMap = (0, import_react5.forwardRef)(({
|
|
2412
2500
|
client,
|
|
2413
2501
|
mapId,
|
|
2414
2502
|
height = "500px",
|
|
@@ -2433,21 +2521,23 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2433
2521
|
onZoomChange,
|
|
2434
2522
|
onMapReady
|
|
2435
2523
|
}, ref) => {
|
|
2436
|
-
const [map, setMap] = (0,
|
|
2437
|
-
const [layers, setLayers] = (0,
|
|
2438
|
-
const [effectiveStates, setEffectiveStates] = (0,
|
|
2439
|
-
const [loadingMap, setLoadingMap] = (0,
|
|
2440
|
-
const [mapError, setMapError] = (0,
|
|
2441
|
-
const [mapInstance, setMapInstance] = (0,
|
|
2442
|
-
const [
|
|
2443
|
-
const
|
|
2444
|
-
const [
|
|
2445
|
-
const [
|
|
2524
|
+
const [map, setMap] = (0, import_react5.useState)(null);
|
|
2525
|
+
const [layers, setLayers] = (0, import_react5.useState)([]);
|
|
2526
|
+
const [effectiveStates, setEffectiveStates] = (0, import_react5.useState)([]);
|
|
2527
|
+
const [loadingMap, setLoadingMap] = (0, import_react5.useState)(false);
|
|
2528
|
+
const [mapError, setMapError] = (0, import_react5.useState)(null);
|
|
2529
|
+
const [mapInstance, setMapInstance] = (0, import_react5.useState)(null);
|
|
2530
|
+
const [layerGeojsonOverrides, setLayerGeojsonOverrides] = (0, import_react5.useState)({});
|
|
2531
|
+
const originalGeojsonByLayerIdRef = (0, import_react5.useRef)({});
|
|
2532
|
+
const [panesReady, setPanesReady] = (0, import_react5.useState)(false);
|
|
2533
|
+
const [currentZoom, setCurrentZoom] = (0, import_react5.useState)(initialZoom ?? DEFAULT_ZOOM);
|
|
2534
|
+
const [isPopupOpen, setIsPopupOpen] = (0, import_react5.useState)(false);
|
|
2535
|
+
const [isMobile, setIsMobile] = (0, import_react5.useState)(() => {
|
|
2446
2536
|
if (typeof window === "undefined") return false;
|
|
2447
2537
|
return window.matchMedia("(max-width: 768px)").matches;
|
|
2448
2538
|
});
|
|
2449
|
-
const normalizedLayers = (0,
|
|
2450
|
-
(0,
|
|
2539
|
+
const normalizedLayers = (0, import_react5.useMemo)(() => normalizeMapLayers(map), [map]);
|
|
2540
|
+
(0, import_react5.useEffect)(() => {
|
|
2451
2541
|
if (typeof window === "undefined") return;
|
|
2452
2542
|
const mql = window.matchMedia("(max-width: 768px)");
|
|
2453
2543
|
const onChange = (e) => {
|
|
@@ -2465,17 +2555,17 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2465
2555
|
}
|
|
2466
2556
|
return;
|
|
2467
2557
|
}, []);
|
|
2468
|
-
(0,
|
|
2558
|
+
(0, import_react5.useEffect)(() => {
|
|
2469
2559
|
if (featureInfoMode === "popup") {
|
|
2470
2560
|
ensurePopupStyles();
|
|
2471
2561
|
}
|
|
2472
2562
|
}, [featureInfoMode]);
|
|
2473
|
-
(0,
|
|
2563
|
+
(0, import_react5.useEffect)(() => {
|
|
2474
2564
|
if (featureInfoMode !== "popup") {
|
|
2475
2565
|
setIsPopupOpen(false);
|
|
2476
2566
|
}
|
|
2477
2567
|
}, [featureInfoMode]);
|
|
2478
|
-
(0,
|
|
2568
|
+
(0, import_react5.useEffect)(() => {
|
|
2479
2569
|
if (!mapInstance) return;
|
|
2480
2570
|
const popupPane = mapInstance.getPane("popupPane");
|
|
2481
2571
|
if (popupPane) {
|
|
@@ -2484,7 +2574,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2484
2574
|
const labelsPane = mapInstance.getPane(LABELS_PANE_NAME) ?? mapInstance.createPane(LABELS_PANE_NAME);
|
|
2485
2575
|
labelsPane.style.zIndex = "600";
|
|
2486
2576
|
}, [mapInstance]);
|
|
2487
|
-
(0,
|
|
2577
|
+
(0, import_react5.useEffect)(() => {
|
|
2488
2578
|
if (!mapInstance) return;
|
|
2489
2579
|
const handlePopupOpen = () => setIsPopupOpen(true);
|
|
2490
2580
|
const handlePopupClose = () => setIsPopupOpen(false);
|
|
@@ -2495,7 +2585,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2495
2585
|
mapInstance.off("popupclose", handlePopupClose);
|
|
2496
2586
|
};
|
|
2497
2587
|
}, [mapInstance]);
|
|
2498
|
-
const layerStyleIndex = (0,
|
|
2588
|
+
const layerStyleIndex = (0, import_react5.useMemo)(() => {
|
|
2499
2589
|
const index = /* @__PURE__ */ new Map();
|
|
2500
2590
|
(map?.mapLayers ?? []).forEach((entry) => {
|
|
2501
2591
|
const layerStyle = entry.layer?.style ?? entry.mapLayer?.layer?.style ?? entry.style ?? null;
|
|
@@ -2506,7 +2596,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2506
2596
|
});
|
|
2507
2597
|
return index;
|
|
2508
2598
|
}, [map]);
|
|
2509
|
-
const labelKeyIndex = (0,
|
|
2599
|
+
const labelKeyIndex = (0, import_react5.useMemo)(() => {
|
|
2510
2600
|
const index = /* @__PURE__ */ new Map();
|
|
2511
2601
|
normalizedLayers.forEach((entry) => {
|
|
2512
2602
|
const label = entry.layer?.label ?? entry.mapLayer?.label ?? entry.mapLayer.layerConfig?.label;
|
|
@@ -2516,7 +2606,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2516
2606
|
});
|
|
2517
2607
|
return index;
|
|
2518
2608
|
}, [normalizedLayers]);
|
|
2519
|
-
const layerMetaIndex = (0,
|
|
2609
|
+
const layerMetaIndex = (0, import_react5.useMemo)(() => {
|
|
2520
2610
|
const index = /* @__PURE__ */ new Map();
|
|
2521
2611
|
normalizedLayers.forEach((entry) => {
|
|
2522
2612
|
index.set(String(entry.layerId), {
|
|
@@ -2526,7 +2616,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2526
2616
|
});
|
|
2527
2617
|
return index;
|
|
2528
2618
|
}, [normalizedLayers]);
|
|
2529
|
-
const overlayStyleFunction = (0,
|
|
2619
|
+
const overlayStyleFunction = (0, import_react5.useMemo)(() => {
|
|
2530
2620
|
return (feature) => {
|
|
2531
2621
|
const featureLayerId = getFeatureLayerId(feature);
|
|
2532
2622
|
const featureStyleOverrides = getFeatureStyleOverrides(feature);
|
|
@@ -2545,15 +2635,15 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2545
2635
|
return defaultOptions;
|
|
2546
2636
|
};
|
|
2547
2637
|
}, [layerStyleIndex, mapLayers, overlayStyle]);
|
|
2548
|
-
const overlayStyleFn = (0,
|
|
2638
|
+
const overlayStyleFn = (0, import_react5.useCallback)(
|
|
2549
2639
|
(feature, _layerType, _baseOpacity) => overlayStyleFunction(feature),
|
|
2550
2640
|
[overlayStyleFunction]
|
|
2551
2641
|
);
|
|
2552
|
-
const [baseStates, setBaseStates] = (0,
|
|
2553
|
-
const [mapOverrides, setMapOverrides] = (0,
|
|
2554
|
-
const [controlOverrides, setControlOverrides] = (0,
|
|
2555
|
-
const [uiOverrides, setUiOverrides] = (0,
|
|
2556
|
-
(0,
|
|
2642
|
+
const [baseStates, setBaseStates] = (0, import_react5.useState)([]);
|
|
2643
|
+
const [mapOverrides, setMapOverrides] = (0, import_react5.useState)([]);
|
|
2644
|
+
const [controlOverrides, setControlOverrides] = (0, import_react5.useState)([]);
|
|
2645
|
+
const [uiOverrides, setUiOverrides] = (0, import_react5.useState)([]);
|
|
2646
|
+
(0, import_react5.useEffect)(() => {
|
|
2557
2647
|
let isMounted = true;
|
|
2558
2648
|
setLoadingMap(true);
|
|
2559
2649
|
setMapError(null);
|
|
@@ -2576,7 +2666,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2576
2666
|
isMounted = false;
|
|
2577
2667
|
};
|
|
2578
2668
|
}, [client.maps, mapId, onError, onLoadingChange]);
|
|
2579
|
-
(0,
|
|
2669
|
+
(0, import_react5.useEffect)(() => {
|
|
2580
2670
|
if (normalizedLayers.length === 0) {
|
|
2581
2671
|
setLayers([]);
|
|
2582
2672
|
setBaseStates([]);
|
|
@@ -2607,7 +2697,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2607
2697
|
setMapOverrides(initialOverrides);
|
|
2608
2698
|
setUiOverrides([]);
|
|
2609
2699
|
}, [normalizedLayers]);
|
|
2610
|
-
(0,
|
|
2700
|
+
(0, import_react5.useEffect)(() => {
|
|
2611
2701
|
if (!layerControls) {
|
|
2612
2702
|
setControlOverrides([]);
|
|
2613
2703
|
return;
|
|
@@ -2619,7 +2709,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2619
2709
|
}));
|
|
2620
2710
|
setControlOverrides(overrides);
|
|
2621
2711
|
}, [layerControls]);
|
|
2622
|
-
(0,
|
|
2712
|
+
(0, import_react5.useEffect)(() => {
|
|
2623
2713
|
if (layerStates) {
|
|
2624
2714
|
return;
|
|
2625
2715
|
}
|
|
@@ -2629,12 +2719,12 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2629
2719
|
onLayerStateChange?.(reset);
|
|
2630
2720
|
}
|
|
2631
2721
|
}, [baseStates, effectiveStates.length, layerControls, layerStates, onLayerStateChange]);
|
|
2632
|
-
(0,
|
|
2722
|
+
(0, import_react5.useEffect)(() => {
|
|
2633
2723
|
if (layerStates) {
|
|
2634
2724
|
setEffectiveStates(layerStates);
|
|
2635
2725
|
}
|
|
2636
2726
|
}, [layerStates]);
|
|
2637
|
-
(0,
|
|
2727
|
+
(0, import_react5.useEffect)(() => {
|
|
2638
2728
|
if (layerStates) {
|
|
2639
2729
|
return;
|
|
2640
2730
|
}
|
|
@@ -2647,11 +2737,11 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2647
2737
|
setEffectiveStates(next);
|
|
2648
2738
|
onLayerStateChange?.(next);
|
|
2649
2739
|
}, [baseStates, controlOverrides, layerStates, mapOverrides, onLayerStateChange, uiOverrides]);
|
|
2650
|
-
(0,
|
|
2740
|
+
(0, import_react5.useEffect)(() => {
|
|
2651
2741
|
if (!Array.isArray(layerControls) || layerControls.length > 0) return;
|
|
2652
2742
|
setUiOverrides([]);
|
|
2653
2743
|
}, [layerControls]);
|
|
2654
|
-
(0,
|
|
2744
|
+
(0, import_react5.useEffect)(() => {
|
|
2655
2745
|
if (layerStates) {
|
|
2656
2746
|
return;
|
|
2657
2747
|
}
|
|
@@ -2671,7 +2761,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2671
2761
|
return [...filtered, nextEntry];
|
|
2672
2762
|
});
|
|
2673
2763
|
};
|
|
2674
|
-
const updateOpacityFromUi = (0,
|
|
2764
|
+
const updateOpacityFromUi = (0, import_react5.useCallback)(
|
|
2675
2765
|
(layerId, uiOpacity) => {
|
|
2676
2766
|
const meta = layerMetaIndex.get(String(layerId));
|
|
2677
2767
|
const baseOpacity = clampOpacity3(uiOpacity);
|
|
@@ -2710,7 +2800,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2710
2800
|
},
|
|
2711
2801
|
[currentZoom, effectiveStates, layerMetaIndex, layerStates, onLayerStateChange]
|
|
2712
2802
|
);
|
|
2713
|
-
const center = (0,
|
|
2803
|
+
const center = (0, import_react5.useMemo)(() => {
|
|
2714
2804
|
if (initialCenter) {
|
|
2715
2805
|
return initialCenter;
|
|
2716
2806
|
}
|
|
@@ -2721,30 +2811,44 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2721
2811
|
return DEFAULT_CENTER;
|
|
2722
2812
|
}, [initialCenter, map?.settings?.center]);
|
|
2723
2813
|
const zoom = initialZoom ?? map?.settings?.zoom ?? DEFAULT_ZOOM;
|
|
2724
|
-
(0,
|
|
2814
|
+
(0, import_react5.useEffect)(() => {
|
|
2725
2815
|
setCurrentZoom(zoom);
|
|
2726
2816
|
}, [zoom]);
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2817
|
+
(0, import_react5.useEffect)(() => {
|
|
2818
|
+
if (!layerGeojson) return;
|
|
2819
|
+
layers.forEach((layer) => {
|
|
2820
|
+
const layerKey = String(layer.mapLayer.layerId);
|
|
2821
|
+
const incoming = layerGeojson[layer.mapLayer.layerId] ?? layerGeojson[layerKey] ?? null;
|
|
2822
|
+
if (incoming && !originalGeojsonByLayerIdRef.current[layerKey]) {
|
|
2823
|
+
originalGeojsonByLayerIdRef.current[layerKey] = incoming;
|
|
2824
|
+
}
|
|
2825
|
+
});
|
|
2826
|
+
}, [layerGeojson, layers]);
|
|
2827
|
+
const decoratedLayers = (0, import_react5.useMemo)(() => {
|
|
2828
|
+
return layers.map((layer) => {
|
|
2829
|
+
const layerKey = String(layer.mapLayer.layerId);
|
|
2830
|
+
const override = layerGeojsonOverrides[layerKey];
|
|
2831
|
+
return {
|
|
2832
|
+
...layer,
|
|
2833
|
+
effective: effectiveStates.find((state) => state.layerId === layer.mapLayer.layerId),
|
|
2834
|
+
data: override ?? layerGeojson?.[layer.mapLayer.layerId] ?? layerGeojson?.[layerKey] ?? null
|
|
2835
|
+
};
|
|
2836
|
+
});
|
|
2837
|
+
}, [effectiveStates, layerGeojson, layerGeojsonOverrides, layers]);
|
|
2838
|
+
const orderedLayers = (0, import_react5.useMemo)(() => {
|
|
2735
2839
|
return [...decoratedLayers].filter((layer) => layer.effective?.visible && layer.data).sort((a, b) => a.displayOrder - b.displayOrder);
|
|
2736
2840
|
}, [decoratedLayers]);
|
|
2737
|
-
const autoZoomGeojson = (0,
|
|
2841
|
+
const autoZoomGeojson = (0, import_react5.useMemo)(
|
|
2738
2842
|
() => orderedLayers.map((layer) => layer.data).filter((collection) => !!collection),
|
|
2739
2843
|
[orderedLayers]
|
|
2740
2844
|
);
|
|
2741
|
-
const resolveLayerStyle = (0,
|
|
2845
|
+
const resolveLayerStyle = (0, import_react5.useCallback)(
|
|
2742
2846
|
(layerId) => {
|
|
2743
2847
|
return getStyleByLayerId(layerId, mapLayers) ?? layerStyleIndex.get(String(layerId)) ?? null;
|
|
2744
2848
|
},
|
|
2745
2849
|
[layerStyleIndex, mapLayers]
|
|
2746
2850
|
);
|
|
2747
|
-
const labelMarkers = (0,
|
|
2851
|
+
const labelMarkers = (0, import_react5.useMemo)(() => {
|
|
2748
2852
|
const markers = [];
|
|
2749
2853
|
decoratedLayers.forEach((layerState) => {
|
|
2750
2854
|
if (!layerState.effective?.visible) return;
|
|
@@ -2781,7 +2885,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2781
2885
|
});
|
|
2782
2886
|
return markers;
|
|
2783
2887
|
}, [currentZoom, decoratedLayers, labelKeyIndex, layerMetaIndex, resolveLayerStyle]);
|
|
2784
|
-
const ensureLayerPanes = (0,
|
|
2888
|
+
const ensureLayerPanes = (0, import_react5.useCallback)(
|
|
2785
2889
|
(targetMap, targetLayers) => {
|
|
2786
2890
|
const baseZIndex = 400;
|
|
2787
2891
|
targetLayers.forEach((layer) => {
|
|
@@ -2797,7 +2901,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2797
2901
|
},
|
|
2798
2902
|
[]
|
|
2799
2903
|
);
|
|
2800
|
-
const handleMapReady = (0,
|
|
2904
|
+
const handleMapReady = (0, import_react5.useCallback)(
|
|
2801
2905
|
(instance) => {
|
|
2802
2906
|
setPanesReady(false);
|
|
2803
2907
|
setMapInstance(instance);
|
|
@@ -2805,7 +2909,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2805
2909
|
},
|
|
2806
2910
|
[onMapReady]
|
|
2807
2911
|
);
|
|
2808
|
-
(0,
|
|
2912
|
+
(0, import_react5.useEffect)(() => {
|
|
2809
2913
|
if (!mapInstance) {
|
|
2810
2914
|
setPanesReady(false);
|
|
2811
2915
|
return;
|
|
@@ -2825,7 +2929,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2825
2929
|
setPanesReady(true);
|
|
2826
2930
|
}
|
|
2827
2931
|
}, [mapInstance, orderedLayers, ensureLayerPanes]);
|
|
2828
|
-
const overlayOnEachFeature = (0,
|
|
2932
|
+
const overlayOnEachFeature = (0, import_react5.useMemo)(() => {
|
|
2829
2933
|
return (feature, layer) => {
|
|
2830
2934
|
const layerId = getFeatureLayerId(feature) ?? void 0;
|
|
2831
2935
|
const geometryType = feature?.geometry?.type;
|
|
@@ -2936,7 +3040,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2936
3040
|
return buildLayerStyle(layerId, baseOpacity ?? 1, feature, layerType);
|
|
2937
3041
|
};
|
|
2938
3042
|
};
|
|
2939
|
-
(0,
|
|
3043
|
+
(0, import_react5.useImperativeHandle)(ref, () => ({
|
|
2940
3044
|
setLayerOpacity: (layerId, opacity) => {
|
|
2941
3045
|
upsertUiOverride(layerId, { overrideOpacity: opacity });
|
|
2942
3046
|
},
|
|
@@ -2959,6 +3063,24 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2959
3063
|
};
|
|
2960
3064
|
mapInstance.fitBounds(bounds, fitOptions);
|
|
2961
3065
|
},
|
|
3066
|
+
fitToBbox: (bbox, padding) => {
|
|
3067
|
+
if (!mapInstance) return;
|
|
3068
|
+
if (typeof bbox.minLat !== "number" || typeof bbox.minLon !== "number" || typeof bbox.maxLat !== "number" || typeof bbox.maxLon !== "number" || !Number.isFinite(bbox.minLat) || !Number.isFinite(bbox.minLon) || !Number.isFinite(bbox.maxLat) || !Number.isFinite(bbox.maxLon)) {
|
|
3069
|
+
console.warn("[ZenitMap.fitToBbox] Invalid bbox", bbox);
|
|
3070
|
+
return;
|
|
3071
|
+
}
|
|
3072
|
+
const resolvedPadding = padding ?? (isMobile ? 40 : 24);
|
|
3073
|
+
const bounds = import_leaflet4.default.latLngBounds([bbox.minLat, bbox.minLon], [bbox.maxLat, bbox.maxLon]);
|
|
3074
|
+
mapInstance.fitBounds(bounds, { padding: [resolvedPadding, resolvedPadding], animate: true });
|
|
3075
|
+
},
|
|
3076
|
+
fitToGeoJson: (fc, padding) => {
|
|
3077
|
+
if (!mapInstance) return;
|
|
3078
|
+
if (!fc?.features?.length) return;
|
|
3079
|
+
const bounds = import_leaflet4.default.geoJSON(fc).getBounds();
|
|
3080
|
+
if (!bounds.isValid()) return;
|
|
3081
|
+
const resolvedPadding = padding ?? (isMobile ? 40 : 24);
|
|
3082
|
+
mapInstance.fitBounds(bounds, { padding: [resolvedPadding, resolvedPadding], animate: true });
|
|
3083
|
+
},
|
|
2962
3084
|
setView: (coordinates, zoom2) => {
|
|
2963
3085
|
if (!mapInstance) return;
|
|
2964
3086
|
mapInstance.setView([coordinates.lat, coordinates.lon], zoom2 ?? mapInstance.getZoom(), {
|
|
@@ -2983,8 +3105,25 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
2983
3105
|
highlightFeature: (layerId, featureId) => {
|
|
2984
3106
|
upsertUiOverride(layerId, { overrideVisible: true, overrideOpacity: 1 });
|
|
2985
3107
|
},
|
|
3108
|
+
updateLayerGeoJson: (layerId, featureCollection) => {
|
|
3109
|
+
const layerKey = String(layerId);
|
|
3110
|
+
setLayerGeojsonOverrides((prev) => ({ ...prev, [layerKey]: featureCollection }));
|
|
3111
|
+
},
|
|
3112
|
+
restoreLayerGeoJson: (layerId) => {
|
|
3113
|
+
const layerKey = String(layerId);
|
|
3114
|
+
const original = originalGeojsonByLayerIdRef.current[layerKey];
|
|
3115
|
+
setLayerGeojsonOverrides((prev) => {
|
|
3116
|
+
const next = { ...prev };
|
|
3117
|
+
if (original) {
|
|
3118
|
+
next[layerKey] = original;
|
|
3119
|
+
} else {
|
|
3120
|
+
delete next[layerKey];
|
|
3121
|
+
}
|
|
3122
|
+
return next;
|
|
3123
|
+
});
|
|
3124
|
+
},
|
|
2986
3125
|
getMapInstance: () => mapInstance
|
|
2987
|
-
}), [effectiveStates, mapInstance]);
|
|
3126
|
+
}), [effectiveStates, isMobile, mapInstance]);
|
|
2988
3127
|
if (loadingMap) {
|
|
2989
3128
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { padding: 16, height, width }, children: "Cargando mapa..." });
|
|
2990
3129
|
}
|
|
@@ -3037,6 +3176,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
3037
3176
|
),
|
|
3038
3177
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_leaflet4.ZoomControl, { position: "topright" }),
|
|
3039
3178
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MapInstanceBridge, { onReady: handleMapReady }),
|
|
3179
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MapInvalidator, { trigger: mapId }),
|
|
3040
3180
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3041
3181
|
BBoxZoomHandler,
|
|
3042
3182
|
{
|
|
@@ -3053,7 +3193,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
3053
3193
|
const pointsPaneName = `zenit-layer-${layerState.mapLayer.layerId}-points`;
|
|
3054
3194
|
const layerType = layerState.layer?.layerType ?? layerState.mapLayer.layerType ?? void 0;
|
|
3055
3195
|
const labelKey = labelKeyIndex.get(String(layerState.mapLayer.layerId));
|
|
3056
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react5.default.Fragment, { children: [
|
|
3057
3197
|
layerState.data && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3058
3198
|
LayerGeoJson,
|
|
3059
3199
|
{
|
|
@@ -3210,7 +3350,7 @@ var ZenitMap = (0, import_react4.forwardRef)(({
|
|
|
3210
3350
|
ZenitMap.displayName = "ZenitMap";
|
|
3211
3351
|
|
|
3212
3352
|
// src/react/ZenitLayerManager.tsx
|
|
3213
|
-
var
|
|
3353
|
+
var import_react6 = __toESM(require("react"));
|
|
3214
3354
|
|
|
3215
3355
|
// src/react/icons.tsx
|
|
3216
3356
|
var import_lucide_react = require("lucide-react");
|
|
@@ -3254,17 +3394,28 @@ var ZenitLayerManager = ({
|
|
|
3254
3394
|
showUploadTab = true,
|
|
3255
3395
|
showLayerVisibilityIcon = true,
|
|
3256
3396
|
layerFeatureCounts,
|
|
3257
|
-
mapLayers
|
|
3397
|
+
mapLayers,
|
|
3398
|
+
onApplyLayerFilter,
|
|
3399
|
+
onClearLayerFilter
|
|
3258
3400
|
}) => {
|
|
3259
|
-
const [map, setMap] = (0,
|
|
3260
|
-
const [loadingMap, setLoadingMap] = (0,
|
|
3261
|
-
const [mapError, setMapError] = (0,
|
|
3262
|
-
const [layers, setLayers] = (0,
|
|
3263
|
-
const [activeTab, setActiveTab] = (0,
|
|
3264
|
-
const [panelVisible, setPanelVisible] = (0,
|
|
3265
|
-
const
|
|
3401
|
+
const [map, setMap] = (0, import_react6.useState)(null);
|
|
3402
|
+
const [loadingMap, setLoadingMap] = (0, import_react6.useState)(false);
|
|
3403
|
+
const [mapError, setMapError] = (0, import_react6.useState)(null);
|
|
3404
|
+
const [layers, setLayers] = (0, import_react6.useState)([]);
|
|
3405
|
+
const [activeTab, setActiveTab] = (0, import_react6.useState)("layers");
|
|
3406
|
+
const [panelVisible, setPanelVisible] = (0, import_react6.useState)(true);
|
|
3407
|
+
const [selectedFilterLayerId, setSelectedFilterLayerId] = (0, import_react6.useState)("");
|
|
3408
|
+
const [selectedFilterField, setSelectedFilterField] = (0, import_react6.useState)("");
|
|
3409
|
+
const [selectedFilterValue, setSelectedFilterValue] = (0, import_react6.useState)("");
|
|
3410
|
+
const [catalogByLayerField, setCatalogByLayerField] = (0, import_react6.useState)({});
|
|
3411
|
+
const [loadingCatalog, setLoadingCatalog] = (0, import_react6.useState)(false);
|
|
3412
|
+
const [applyingFilter, setApplyingFilter] = (0, import_react6.useState)(false);
|
|
3413
|
+
const [filterError, setFilterError] = (0, import_react6.useState)(null);
|
|
3414
|
+
const [appliedFilter, setAppliedFilter] = (0, import_react6.useState)(null);
|
|
3415
|
+
const catalogAbortRef = (0, import_react6.useRef)(null);
|
|
3416
|
+
const lastEmittedStatesRef = (0, import_react6.useRef)(null);
|
|
3266
3417
|
const isControlled = Array.isArray(layerStates) && typeof onLayerStatesChange === "function";
|
|
3267
|
-
const baseStates = (0,
|
|
3418
|
+
const baseStates = (0, import_react6.useMemo)(
|
|
3268
3419
|
() => initLayerStates(
|
|
3269
3420
|
layers.map((entry) => ({
|
|
3270
3421
|
...entry.mapLayer,
|
|
@@ -3275,7 +3426,7 @@ var ZenitLayerManager = ({
|
|
|
3275
3426
|
),
|
|
3276
3427
|
[layers]
|
|
3277
3428
|
);
|
|
3278
|
-
const overrideStates = (0,
|
|
3429
|
+
const overrideStates = (0, import_react6.useMemo)(
|
|
3279
3430
|
() => layers.map(
|
|
3280
3431
|
(entry) => ({
|
|
3281
3432
|
layerId: entry.mapLayer.layerId,
|
|
@@ -3285,11 +3436,11 @@ var ZenitLayerManager = ({
|
|
|
3285
3436
|
),
|
|
3286
3437
|
[layers]
|
|
3287
3438
|
);
|
|
3288
|
-
const effectiveStates = (0,
|
|
3439
|
+
const effectiveStates = (0, import_react6.useMemo)(
|
|
3289
3440
|
() => layerStates ?? applyLayerOverrides(baseStates, overrideStates),
|
|
3290
3441
|
[baseStates, layerStates, overrideStates]
|
|
3291
3442
|
);
|
|
3292
|
-
const layerMetaIndex = (0,
|
|
3443
|
+
const layerMetaIndex = (0, import_react6.useMemo)(() => {
|
|
3293
3444
|
const index = /* @__PURE__ */ new Map();
|
|
3294
3445
|
mapLayers?.forEach((entry) => {
|
|
3295
3446
|
const key = String(entry.layerId);
|
|
@@ -3303,7 +3454,7 @@ var ZenitLayerManager = ({
|
|
|
3303
3454
|
});
|
|
3304
3455
|
return index;
|
|
3305
3456
|
}, [map, mapLayers]);
|
|
3306
|
-
const resolveUserOpacity =
|
|
3457
|
+
const resolveUserOpacity = import_react6.default.useCallback((state) => {
|
|
3307
3458
|
if (typeof state.overrideOpacity === "number") return state.overrideOpacity;
|
|
3308
3459
|
if (typeof state.overrideOpacity === "string") {
|
|
3309
3460
|
const parsed = Number.parseFloat(state.overrideOpacity);
|
|
@@ -3311,7 +3462,7 @@ var ZenitLayerManager = ({
|
|
|
3311
3462
|
}
|
|
3312
3463
|
return state.opacity ?? 1;
|
|
3313
3464
|
}, []);
|
|
3314
|
-
const resolveEffectiveOpacity =
|
|
3465
|
+
const resolveEffectiveOpacity = import_react6.default.useCallback(
|
|
3315
3466
|
(layerId, userOpacity) => {
|
|
3316
3467
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
3317
3468
|
return userOpacity;
|
|
@@ -3327,7 +3478,7 @@ var ZenitLayerManager = ({
|
|
|
3327
3478
|
},
|
|
3328
3479
|
[autoOpacityConfig, autoOpacityOnZoom, layerMetaIndex, mapZoom]
|
|
3329
3480
|
);
|
|
3330
|
-
const effectiveStatesWithZoom = (0,
|
|
3481
|
+
const effectiveStatesWithZoom = (0, import_react6.useMemo)(() => {
|
|
3331
3482
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
3332
3483
|
return effectiveStates;
|
|
3333
3484
|
}
|
|
@@ -3341,7 +3492,7 @@ var ZenitLayerManager = ({
|
|
|
3341
3492
|
};
|
|
3342
3493
|
});
|
|
3343
3494
|
}, [autoOpacityOnZoom, effectiveStates, mapZoom, resolveEffectiveOpacity, resolveUserOpacity]);
|
|
3344
|
-
(0,
|
|
3495
|
+
(0, import_react6.useEffect)(() => {
|
|
3345
3496
|
let cancelled = false;
|
|
3346
3497
|
setLoadingMap(true);
|
|
3347
3498
|
setMapError(null);
|
|
@@ -3373,12 +3524,12 @@ var ZenitLayerManager = ({
|
|
|
3373
3524
|
cancelled = true;
|
|
3374
3525
|
};
|
|
3375
3526
|
}, [client.maps, mapId]);
|
|
3376
|
-
(0,
|
|
3527
|
+
(0, import_react6.useEffect)(() => {
|
|
3377
3528
|
if (!showUploadTab && activeTab === "upload") {
|
|
3378
3529
|
setActiveTab("layers");
|
|
3379
3530
|
}
|
|
3380
3531
|
}, [activeTab, showUploadTab]);
|
|
3381
|
-
(0,
|
|
3532
|
+
(0, import_react6.useEffect)(() => {
|
|
3382
3533
|
if (isControlled) return;
|
|
3383
3534
|
if (!onLayerStatesChange) return;
|
|
3384
3535
|
const emitStates = autoOpacityOnZoom && typeof mapZoom === "number" ? effectiveStatesWithZoom : effectiveStates;
|
|
@@ -3396,7 +3547,7 @@ var ZenitLayerManager = ({
|
|
|
3396
3547
|
mapZoom,
|
|
3397
3548
|
onLayerStatesChange
|
|
3398
3549
|
]);
|
|
3399
|
-
const updateLayerVisible =
|
|
3550
|
+
const updateLayerVisible = import_react6.default.useCallback(
|
|
3400
3551
|
(layerId, visible) => {
|
|
3401
3552
|
if (!onLayerStatesChange) return;
|
|
3402
3553
|
const next = effectiveStates.map(
|
|
@@ -3406,7 +3557,7 @@ var ZenitLayerManager = ({
|
|
|
3406
3557
|
},
|
|
3407
3558
|
[effectiveStates, onLayerStatesChange]
|
|
3408
3559
|
);
|
|
3409
|
-
const updateLayerOpacity =
|
|
3560
|
+
const updateLayerOpacity = import_react6.default.useCallback(
|
|
3410
3561
|
(layerId, opacity) => {
|
|
3411
3562
|
if (!onLayerStatesChange) return;
|
|
3412
3563
|
const adjustedOpacity = resolveEffectiveOpacity(layerId, opacity);
|
|
@@ -3417,7 +3568,7 @@ var ZenitLayerManager = ({
|
|
|
3417
3568
|
},
|
|
3418
3569
|
[effectiveStates, onLayerStatesChange, resolveEffectiveOpacity]
|
|
3419
3570
|
);
|
|
3420
|
-
const resolveFeatureCount =
|
|
3571
|
+
const resolveFeatureCount = import_react6.default.useCallback(
|
|
3421
3572
|
(layerId, layer) => {
|
|
3422
3573
|
const resolvedFeatureCount = layerFeatureCounts?.[layerId] ?? layerFeatureCounts?.[String(layerId)];
|
|
3423
3574
|
if (typeof resolvedFeatureCount === "number") return resolvedFeatureCount;
|
|
@@ -3426,7 +3577,7 @@ var ZenitLayerManager = ({
|
|
|
3426
3577
|
},
|
|
3427
3578
|
[layerFeatureCounts]
|
|
3428
3579
|
);
|
|
3429
|
-
const decoratedLayers = (0,
|
|
3580
|
+
const decoratedLayers = (0, import_react6.useMemo)(() => {
|
|
3430
3581
|
return layers.map((entry) => ({
|
|
3431
3582
|
...entry,
|
|
3432
3583
|
effective: effectiveStates.find((state) => state.layerId === entry.mapLayer.layerId),
|
|
@@ -3455,7 +3606,140 @@ var ZenitLayerManager = ({
|
|
|
3455
3606
|
return String(a.mapLayer.layerId).localeCompare(String(b.mapLayer.layerId));
|
|
3456
3607
|
});
|
|
3457
3608
|
}, [effectiveStates, layers, resolveFeatureCount]);
|
|
3458
|
-
const
|
|
3609
|
+
const filterableLayers = (0, import_react6.useMemo)(() => {
|
|
3610
|
+
return decoratedLayers.filter((entry) => {
|
|
3611
|
+
const prefilters = entry.mapLayer.layerConfig?.prefilters;
|
|
3612
|
+
return !!prefilters && Object.keys(prefilters).length > 0;
|
|
3613
|
+
});
|
|
3614
|
+
}, [decoratedLayers]);
|
|
3615
|
+
const selectedFilterLayer = (0, import_react6.useMemo)(
|
|
3616
|
+
() => filterableLayers.find((layer) => String(layer.mapLayer.layerId) === selectedFilterLayerId) ?? null,
|
|
3617
|
+
[filterableLayers, selectedFilterLayerId]
|
|
3618
|
+
);
|
|
3619
|
+
const filterFields = (0, import_react6.useMemo)(() => {
|
|
3620
|
+
const prefilters = selectedFilterLayer?.mapLayer.layerConfig?.prefilters;
|
|
3621
|
+
return prefilters ? Object.keys(prefilters) : [];
|
|
3622
|
+
}, [selectedFilterLayer]);
|
|
3623
|
+
const activeCatalogKey = selectedFilterLayer ? `${selectedFilterLayer.mapLayer.layerId}:${selectedFilterField}` : null;
|
|
3624
|
+
const activeCatalogValues = activeCatalogKey ? catalogByLayerField[activeCatalogKey] ?? [] : [];
|
|
3625
|
+
const extractCatalogValues = import_react6.default.useCallback((catalogData, field) => {
|
|
3626
|
+
const values = /* @__PURE__ */ new Set();
|
|
3627
|
+
const pushValue = (value) => {
|
|
3628
|
+
if (value === null || value === void 0) return;
|
|
3629
|
+
const normalized = String(value).trim();
|
|
3630
|
+
if (normalized) values.add(normalized);
|
|
3631
|
+
};
|
|
3632
|
+
if (catalogData && typeof catalogData === "object") {
|
|
3633
|
+
const maybeRecord = catalogData;
|
|
3634
|
+
const directField = maybeRecord[field];
|
|
3635
|
+
if (Array.isArray(directField)) {
|
|
3636
|
+
directField.forEach(pushValue);
|
|
3637
|
+
}
|
|
3638
|
+
const items = maybeRecord.items;
|
|
3639
|
+
if (Array.isArray(items)) {
|
|
3640
|
+
items.forEach((item) => {
|
|
3641
|
+
if (!item || typeof item !== "object") return;
|
|
3642
|
+
const row = item;
|
|
3643
|
+
const rowField = row.field;
|
|
3644
|
+
if (String(rowField ?? "").toUpperCase() === field.toUpperCase() && Array.isArray(row.values)) {
|
|
3645
|
+
row.values.forEach(pushValue);
|
|
3646
|
+
}
|
|
3647
|
+
});
|
|
3648
|
+
}
|
|
3649
|
+
const features = maybeRecord.features;
|
|
3650
|
+
if (Array.isArray(features)) {
|
|
3651
|
+
features.forEach((feature) => {
|
|
3652
|
+
if (!feature || typeof feature !== "object") return;
|
|
3653
|
+
const properties = feature.properties;
|
|
3654
|
+
if (properties && field in properties) {
|
|
3655
|
+
pushValue(properties[field]);
|
|
3656
|
+
}
|
|
3657
|
+
});
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
3660
|
+
return [...values].sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
3661
|
+
}, []);
|
|
3662
|
+
(0, import_react6.useEffect)(() => {
|
|
3663
|
+
if (!filterableLayers.length) {
|
|
3664
|
+
setSelectedFilterLayerId("");
|
|
3665
|
+
return;
|
|
3666
|
+
}
|
|
3667
|
+
if (!selectedFilterLayerId || !filterableLayers.some((layer) => String(layer.mapLayer.layerId) === selectedFilterLayerId)) {
|
|
3668
|
+
setSelectedFilterLayerId(String(filterableLayers[0].mapLayer.layerId));
|
|
3669
|
+
}
|
|
3670
|
+
}, [filterableLayers, selectedFilterLayerId]);
|
|
3671
|
+
(0, import_react6.useEffect)(() => {
|
|
3672
|
+
if (!filterFields.length) {
|
|
3673
|
+
setSelectedFilterField("");
|
|
3674
|
+
return;
|
|
3675
|
+
}
|
|
3676
|
+
if (!selectedFilterField || !filterFields.includes(selectedFilterField)) {
|
|
3677
|
+
setSelectedFilterField(filterFields[0]);
|
|
3678
|
+
setSelectedFilterValue("");
|
|
3679
|
+
}
|
|
3680
|
+
}, [filterFields, selectedFilterField]);
|
|
3681
|
+
(0, import_react6.useEffect)(() => {
|
|
3682
|
+
if (activeTab !== "filters") return;
|
|
3683
|
+
if (!selectedFilterLayer || !selectedFilterField || !activeCatalogKey) return;
|
|
3684
|
+
if (catalogByLayerField[activeCatalogKey]) return;
|
|
3685
|
+
catalogAbortRef.current?.abort();
|
|
3686
|
+
const controller = new AbortController();
|
|
3687
|
+
catalogAbortRef.current = controller;
|
|
3688
|
+
setLoadingCatalog(true);
|
|
3689
|
+
setFilterError(null);
|
|
3690
|
+
client.layers.getLayerFeaturesCatalog(selectedFilterLayer.mapLayer.layerId).then((response) => {
|
|
3691
|
+
if (controller.signal.aborted) return;
|
|
3692
|
+
const values = extractCatalogValues(response.data, selectedFilterField);
|
|
3693
|
+
setCatalogByLayerField((prev) => ({ ...prev, [activeCatalogKey]: values }));
|
|
3694
|
+
}).catch((error) => {
|
|
3695
|
+
if (controller.signal.aborted) return;
|
|
3696
|
+
const message = error instanceof Error ? error.message : "No se pudo cargar el cat\xE1logo";
|
|
3697
|
+
setFilterError(message);
|
|
3698
|
+
}).finally(() => {
|
|
3699
|
+
if (!controller.signal.aborted) setLoadingCatalog(false);
|
|
3700
|
+
});
|
|
3701
|
+
return () => {
|
|
3702
|
+
controller.abort();
|
|
3703
|
+
};
|
|
3704
|
+
}, [activeCatalogKey, activeTab, catalogByLayerField, client.layers, extractCatalogValues, selectedFilterField, selectedFilterLayer]);
|
|
3705
|
+
const handleApplyFilter = import_react6.default.useCallback(async () => {
|
|
3706
|
+
if (!selectedFilterLayer || !selectedFilterField || !selectedFilterValue || !onApplyLayerFilter) return;
|
|
3707
|
+
setApplyingFilter(true);
|
|
3708
|
+
setFilterError(null);
|
|
3709
|
+
try {
|
|
3710
|
+
await onApplyLayerFilter({
|
|
3711
|
+
layerId: selectedFilterLayer.mapLayer.layerId,
|
|
3712
|
+
field: selectedFilterField,
|
|
3713
|
+
value: selectedFilterValue
|
|
3714
|
+
});
|
|
3715
|
+
setAppliedFilter({
|
|
3716
|
+
layerId: selectedFilterLayer.mapLayer.layerId,
|
|
3717
|
+
field: selectedFilterField,
|
|
3718
|
+
value: selectedFilterValue
|
|
3719
|
+
});
|
|
3720
|
+
} catch (error) {
|
|
3721
|
+
const message = error instanceof Error ? error.message : "No se pudo aplicar el filtro";
|
|
3722
|
+
setFilterError(message);
|
|
3723
|
+
} finally {
|
|
3724
|
+
setApplyingFilter(false);
|
|
3725
|
+
}
|
|
3726
|
+
}, [onApplyLayerFilter, selectedFilterField, selectedFilterLayer, selectedFilterValue]);
|
|
3727
|
+
const handleClearFilter = import_react6.default.useCallback(async () => {
|
|
3728
|
+
if (!selectedFilterLayer) return;
|
|
3729
|
+
setApplyingFilter(true);
|
|
3730
|
+
setFilterError(null);
|
|
3731
|
+
try {
|
|
3732
|
+
await onClearLayerFilter?.({ layerId: selectedFilterLayer.mapLayer.layerId, field: selectedFilterField || void 0 });
|
|
3733
|
+
setSelectedFilterValue("");
|
|
3734
|
+
setAppliedFilter(null);
|
|
3735
|
+
} catch (error) {
|
|
3736
|
+
const message = error instanceof Error ? error.message : "No se pudo limpiar el filtro";
|
|
3737
|
+
setFilterError(message);
|
|
3738
|
+
} finally {
|
|
3739
|
+
setApplyingFilter(false);
|
|
3740
|
+
}
|
|
3741
|
+
}, [onClearLayerFilter, selectedFilterField, selectedFilterLayer]);
|
|
3742
|
+
const resolveLayerStyle = import_react6.default.useCallback(
|
|
3459
3743
|
(layerId) => {
|
|
3460
3744
|
const layerKey = String(layerId);
|
|
3461
3745
|
const fromProp = mapLayers?.find((entry) => String(entry.layerId) === layerKey)?.style;
|
|
@@ -3793,6 +4077,18 @@ var ZenitLayerManager = ({
|
|
|
3793
4077
|
"Subir"
|
|
3794
4078
|
]
|
|
3795
4079
|
}
|
|
4080
|
+
),
|
|
4081
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
4082
|
+
"button",
|
|
4083
|
+
{
|
|
4084
|
+
type: "button",
|
|
4085
|
+
className: `zlm-tab${activeTab === "filters" ? " is-active" : ""}`,
|
|
4086
|
+
onClick: () => setActiveTab("filters"),
|
|
4087
|
+
children: [
|
|
4088
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Layers, { size: 16 }),
|
|
4089
|
+
"Filtros"
|
|
4090
|
+
]
|
|
4091
|
+
}
|
|
3796
4092
|
)
|
|
3797
4093
|
]
|
|
3798
4094
|
}
|
|
@@ -3800,6 +4096,68 @@ var ZenitLayerManager = ({
|
|
|
3800
4096
|
] }),
|
|
3801
4097
|
panelVisible && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
|
|
3802
4098
|
activeTab === "layers" && renderLayerCards(),
|
|
4099
|
+
activeTab === "filters" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "zlm-filter-panel", style: { display: "flex", flexDirection: "column", gap: 10, background: "#fff", border: "1px solid #e2e8f0", borderRadius: 12, padding: 12 }, children: !filterableLayers.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#64748b", fontSize: 13 }, children: "No hay filtros disponibles para las capas de este mapa." }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
4100
|
+
filterableLayers.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
|
|
4101
|
+
"Capa",
|
|
4102
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("select", { className: "zlm-filter-select", value: selectedFilterLayerId, onChange: (e) => setSelectedFilterLayerId(e.target.value), children: filterableLayers.map((layer) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: String(layer.mapLayer.layerId), children: layer.layerName ?? `Capa ${layer.mapLayer.layerId}` }, String(layer.mapLayer.layerId))) })
|
|
4103
|
+
] }),
|
|
4104
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
|
|
4105
|
+
"Campo",
|
|
4106
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("select", { className: "zlm-filter-select", value: selectedFilterField, onChange: (e) => {
|
|
4107
|
+
setSelectedFilterField(e.target.value);
|
|
4108
|
+
setSelectedFilterValue("");
|
|
4109
|
+
}, children: filterFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: field, children: field }, field)) })
|
|
4110
|
+
] }),
|
|
4111
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
|
|
4112
|
+
"Valor",
|
|
4113
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
4114
|
+
"select",
|
|
4115
|
+
{
|
|
4116
|
+
className: "zlm-filter-select",
|
|
4117
|
+
value: selectedFilterValue,
|
|
4118
|
+
onChange: (e) => {
|
|
4119
|
+
const value = e.target.value;
|
|
4120
|
+
setSelectedFilterValue(value);
|
|
4121
|
+
},
|
|
4122
|
+
children: [
|
|
4123
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "", children: "Seleccionar\u2026" }),
|
|
4124
|
+
activeCatalogValues.map((value) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value, children: value }, value))
|
|
4125
|
+
]
|
|
4126
|
+
}
|
|
4127
|
+
)
|
|
4128
|
+
] }),
|
|
4129
|
+
loadingCatalog && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#64748b", fontSize: 12 }, children: "Cargando cat\xE1logo\u2026" }),
|
|
4130
|
+
!loadingCatalog && selectedFilterField && activeCatalogValues.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#64748b", fontSize: 12 }, children: "No hay cat\xE1logo disponible para este filtro." }),
|
|
4131
|
+
filterError && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#b91c1c", fontSize: 12 }, children: filterError }),
|
|
4132
|
+
appliedFilter && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "zlm-badge", style: { alignSelf: "flex-start" }, children: [
|
|
4133
|
+
"Activo: ",
|
|
4134
|
+
appliedFilter.field,
|
|
4135
|
+
" = ",
|
|
4136
|
+
appliedFilter.value
|
|
4137
|
+
] }),
|
|
4138
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "zlm-filter-actions", style: { display: "flex", gap: 8 }, children: [
|
|
4139
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4140
|
+
"button",
|
|
4141
|
+
{
|
|
4142
|
+
type: "button",
|
|
4143
|
+
className: "zlm-panel-toggle",
|
|
4144
|
+
disabled: !selectedFilterValue || applyingFilter || !onApplyLayerFilter,
|
|
4145
|
+
onClick: handleApplyFilter,
|
|
4146
|
+
children: applyingFilter ? "Aplicando\u2026" : "Aplicar"
|
|
4147
|
+
}
|
|
4148
|
+
),
|
|
4149
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4150
|
+
"button",
|
|
4151
|
+
{
|
|
4152
|
+
type: "button",
|
|
4153
|
+
className: "zlm-panel-toggle",
|
|
4154
|
+
disabled: applyingFilter,
|
|
4155
|
+
onClick: handleClearFilter,
|
|
4156
|
+
children: "Limpiar"
|
|
4157
|
+
}
|
|
4158
|
+
)
|
|
4159
|
+
] })
|
|
4160
|
+
] }) }),
|
|
3803
4161
|
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." })
|
|
3804
4162
|
] })
|
|
3805
4163
|
] });
|
|
@@ -3838,15 +4196,15 @@ var ZenitFeatureFilterPanel = ({
|
|
|
3838
4196
|
};
|
|
3839
4197
|
|
|
3840
4198
|
// src/react/ai/FloatingChatBox.tsx
|
|
3841
|
-
var
|
|
4199
|
+
var import_react8 = require("react");
|
|
3842
4200
|
var import_react_dom2 = require("react-dom");
|
|
3843
4201
|
|
|
3844
4202
|
// src/react/hooks/use-chat.ts
|
|
3845
|
-
var
|
|
4203
|
+
var import_react7 = require("react");
|
|
3846
4204
|
var useSendMessage = (config) => {
|
|
3847
|
-
const [isLoading, setIsLoading] = (0,
|
|
3848
|
-
const [error, setError] = (0,
|
|
3849
|
-
const send = (0,
|
|
4205
|
+
const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
|
|
4206
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
4207
|
+
const send = (0, import_react7.useCallback)(
|
|
3850
4208
|
async (mapId, request, options) => {
|
|
3851
4209
|
setIsLoading(true);
|
|
3852
4210
|
setError(null);
|
|
@@ -3864,18 +4222,18 @@ var useSendMessage = (config) => {
|
|
|
3864
4222
|
return { sendMessage: send, isLoading, error };
|
|
3865
4223
|
};
|
|
3866
4224
|
var useSendMessageStream = (config) => {
|
|
3867
|
-
const [isStreaming, setIsStreaming] = (0,
|
|
3868
|
-
const [streamingText, setStreamingText] = (0,
|
|
3869
|
-
const [completeResponse, setCompleteResponse] = (0,
|
|
3870
|
-
const [error, setError] = (0,
|
|
3871
|
-
const requestIdRef = (0,
|
|
3872
|
-
const reset = (0,
|
|
4225
|
+
const [isStreaming, setIsStreaming] = (0, import_react7.useState)(false);
|
|
4226
|
+
const [streamingText, setStreamingText] = (0, import_react7.useState)("");
|
|
4227
|
+
const [completeResponse, setCompleteResponse] = (0, import_react7.useState)(null);
|
|
4228
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
4229
|
+
const requestIdRef = (0, import_react7.useRef)(0);
|
|
4230
|
+
const reset = (0, import_react7.useCallback)(() => {
|
|
3873
4231
|
setIsStreaming(false);
|
|
3874
4232
|
setStreamingText("");
|
|
3875
4233
|
setCompleteResponse(null);
|
|
3876
4234
|
setError(null);
|
|
3877
4235
|
}, []);
|
|
3878
|
-
const send = (0,
|
|
4236
|
+
const send = (0, import_react7.useCallback)(
|
|
3879
4237
|
async (mapId, request, options) => {
|
|
3880
4238
|
const requestId = requestIdRef.current + 1;
|
|
3881
4239
|
requestIdRef.current = requestId;
|
|
@@ -4166,6 +4524,17 @@ var styles = {
|
|
|
4166
4524
|
width: 480,
|
|
4167
4525
|
height: 640
|
|
4168
4526
|
},
|
|
4527
|
+
panelMobileFullscreen: {
|
|
4528
|
+
position: "fixed",
|
|
4529
|
+
top: 0,
|
|
4530
|
+
left: 0,
|
|
4531
|
+
right: 0,
|
|
4532
|
+
bottom: 0,
|
|
4533
|
+
width: "100%",
|
|
4534
|
+
height: "100%",
|
|
4535
|
+
borderRadius: 0,
|
|
4536
|
+
margin: 0
|
|
4537
|
+
},
|
|
4169
4538
|
// Header with green gradient
|
|
4170
4539
|
header: {
|
|
4171
4540
|
padding: "14px 16px",
|
|
@@ -4399,42 +4768,42 @@ var FloatingChatBox = ({
|
|
|
4399
4768
|
open: openProp
|
|
4400
4769
|
}) => {
|
|
4401
4770
|
const isControlled = openProp !== void 0;
|
|
4402
|
-
const [internalOpen, setInternalOpen] = (0,
|
|
4771
|
+
const [internalOpen, setInternalOpen] = (0, import_react8.useState)(false);
|
|
4403
4772
|
const open = isControlled ? openProp : internalOpen;
|
|
4404
|
-
const setOpen = (0,
|
|
4773
|
+
const setOpen = (0, import_react8.useCallback)((value) => {
|
|
4405
4774
|
const newValue = typeof value === "function" ? value(open) : value;
|
|
4406
4775
|
if (!isControlled) {
|
|
4407
4776
|
setInternalOpen(newValue);
|
|
4408
4777
|
}
|
|
4409
4778
|
onOpenChange?.(newValue);
|
|
4410
4779
|
}, [isControlled, open, onOpenChange]);
|
|
4411
|
-
const [expanded, setExpanded] = (0,
|
|
4412
|
-
const [messages, setMessages] = (0,
|
|
4413
|
-
const [inputValue, setInputValue] = (0,
|
|
4414
|
-
const [conversationId, setConversationId] = (0,
|
|
4415
|
-
const [errorMessage, setErrorMessage] = (0,
|
|
4416
|
-
const [isFocused, setIsFocused] = (0,
|
|
4417
|
-
const [isMobile, setIsMobile] = (0,
|
|
4418
|
-
const messagesEndRef = (0,
|
|
4419
|
-
const messagesContainerRef = (0,
|
|
4420
|
-
const chatBoxRef = (0,
|
|
4421
|
-
const chatConfig = (0,
|
|
4780
|
+
const [expanded, setExpanded] = (0, import_react8.useState)(false);
|
|
4781
|
+
const [messages, setMessages] = (0, import_react8.useState)([]);
|
|
4782
|
+
const [inputValue, setInputValue] = (0, import_react8.useState)("");
|
|
4783
|
+
const [conversationId, setConversationId] = (0, import_react8.useState)();
|
|
4784
|
+
const [errorMessage, setErrorMessage] = (0, import_react8.useState)(null);
|
|
4785
|
+
const [isFocused, setIsFocused] = (0, import_react8.useState)(false);
|
|
4786
|
+
const [isMobile, setIsMobile] = (0, import_react8.useState)(false);
|
|
4787
|
+
const messagesEndRef = (0, import_react8.useRef)(null);
|
|
4788
|
+
const messagesContainerRef = (0, import_react8.useRef)(null);
|
|
4789
|
+
const chatBoxRef = (0, import_react8.useRef)(null);
|
|
4790
|
+
const chatConfig = (0, import_react8.useMemo)(() => {
|
|
4422
4791
|
if (!baseUrl) return void 0;
|
|
4423
4792
|
return { baseUrl, accessToken, getAccessToken };
|
|
4424
4793
|
}, [accessToken, baseUrl, getAccessToken]);
|
|
4425
4794
|
const { sendMessage: sendMessage2, isStreaming, streamingText, completeResponse } = useSendMessageStream(chatConfig);
|
|
4426
4795
|
const canSend = Boolean(mapId) && Boolean(baseUrl) && inputValue.trim().length > 0 && !isStreaming;
|
|
4427
|
-
(0,
|
|
4796
|
+
(0, import_react8.useEffect)(() => {
|
|
4428
4797
|
if (open && isMobile) {
|
|
4429
4798
|
setExpanded(true);
|
|
4430
4799
|
}
|
|
4431
4800
|
}, [open, isMobile]);
|
|
4432
|
-
const scrollToBottom = (0,
|
|
4801
|
+
const scrollToBottom = (0, import_react8.useCallback)(() => {
|
|
4433
4802
|
if (messagesEndRef.current) {
|
|
4434
4803
|
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
4435
4804
|
}
|
|
4436
4805
|
}, []);
|
|
4437
|
-
(0,
|
|
4806
|
+
(0, import_react8.useEffect)(() => {
|
|
4438
4807
|
if (open && messages.length === 0) {
|
|
4439
4808
|
setMessages([
|
|
4440
4809
|
{
|
|
@@ -4445,10 +4814,10 @@ var FloatingChatBox = ({
|
|
|
4445
4814
|
]);
|
|
4446
4815
|
}
|
|
4447
4816
|
}, [open, messages.length]);
|
|
4448
|
-
(0,
|
|
4817
|
+
(0, import_react8.useEffect)(() => {
|
|
4449
4818
|
scrollToBottom();
|
|
4450
4819
|
}, [messages, streamingText, scrollToBottom]);
|
|
4451
|
-
(0,
|
|
4820
|
+
(0, import_react8.useEffect)(() => {
|
|
4452
4821
|
if (!open) return;
|
|
4453
4822
|
if (isMobile && expanded) return;
|
|
4454
4823
|
const handleClickOutside = (event) => {
|
|
@@ -4461,7 +4830,7 @@ var FloatingChatBox = ({
|
|
|
4461
4830
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
4462
4831
|
};
|
|
4463
4832
|
}, [open, isMobile, expanded]);
|
|
4464
|
-
(0,
|
|
4833
|
+
(0, import_react8.useEffect)(() => {
|
|
4465
4834
|
if (typeof window === "undefined") return;
|
|
4466
4835
|
const mediaQuery = window.matchMedia("(max-width: 768px)");
|
|
4467
4836
|
const updateMobile = () => setIsMobile(mediaQuery.matches);
|
|
@@ -4479,7 +4848,7 @@ var FloatingChatBox = ({
|
|
|
4479
4848
|
}
|
|
4480
4849
|
};
|
|
4481
4850
|
}, []);
|
|
4482
|
-
(0,
|
|
4851
|
+
(0, import_react8.useEffect)(() => {
|
|
4483
4852
|
if (typeof document === "undefined") return;
|
|
4484
4853
|
if (!open || !isMobile) return;
|
|
4485
4854
|
document.body.style.overflow = "hidden";
|
|
@@ -4487,10 +4856,10 @@ var FloatingChatBox = ({
|
|
|
4487
4856
|
document.body.style.overflow = "";
|
|
4488
4857
|
};
|
|
4489
4858
|
}, [open, isMobile]);
|
|
4490
|
-
const addMessage = (0,
|
|
4859
|
+
const addMessage = (0, import_react8.useCallback)((message) => {
|
|
4491
4860
|
setMessages((prev) => [...prev, message]);
|
|
4492
4861
|
}, []);
|
|
4493
|
-
const handleSend = (0,
|
|
4862
|
+
const handleSend = (0, import_react8.useCallback)(async () => {
|
|
4494
4863
|
if (!mapId) {
|
|
4495
4864
|
setErrorMessage("Selecciona un mapa para usar el asistente.");
|
|
4496
4865
|
return;
|
|
@@ -4543,7 +4912,7 @@ var FloatingChatBox = ({
|
|
|
4543
4912
|
sendMessage2,
|
|
4544
4913
|
userId
|
|
4545
4914
|
]);
|
|
4546
|
-
const handleKeyDown = (0,
|
|
4915
|
+
const handleKeyDown = (0, import_react8.useCallback)(
|
|
4547
4916
|
(event) => {
|
|
4548
4917
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
4549
4918
|
event.preventDefault();
|
|
@@ -4554,7 +4923,7 @@ var FloatingChatBox = ({
|
|
|
4554
4923
|
},
|
|
4555
4924
|
[canSend, handleSend]
|
|
4556
4925
|
);
|
|
4557
|
-
const handleFollowUpClick = (0,
|
|
4926
|
+
const handleFollowUpClick = (0, import_react8.useCallback)((question) => {
|
|
4558
4927
|
setInputValue(question);
|
|
4559
4928
|
}, []);
|
|
4560
4929
|
const renderMetadata = (response) => {
|
|
@@ -4576,7 +4945,7 @@ var FloatingChatBox = ({
|
|
|
4576
4945
|
] }, index)) })
|
|
4577
4946
|
] });
|
|
4578
4947
|
};
|
|
4579
|
-
const handleActionClick = (0,
|
|
4948
|
+
const handleActionClick = (0, import_react8.useCallback)((action) => {
|
|
4580
4949
|
if (isStreaming) return;
|
|
4581
4950
|
setOpen(false);
|
|
4582
4951
|
requestAnimationFrame(() => {
|
|
@@ -4691,22 +5060,6 @@ var FloatingChatBox = ({
|
|
|
4691
5060
|
box-sizing: border-box;
|
|
4692
5061
|
}
|
|
4693
5062
|
@media (max-width: 768px) {
|
|
4694
|
-
.zenit-chat-panel.zenit-chat-panel--fullscreen {
|
|
4695
|
-
position: fixed !important;
|
|
4696
|
-
left: 0 !important;
|
|
4697
|
-
right: 0 !important;
|
|
4698
|
-
top: 4rem !important;
|
|
4699
|
-
bottom: 0 !important;
|
|
4700
|
-
width: 100% !important;
|
|
4701
|
-
max-width: 100% !important;
|
|
4702
|
-
height: auto !important;
|
|
4703
|
-
border-radius: 0 !important;
|
|
4704
|
-
display: flex !important;
|
|
4705
|
-
flex-direction: column !important;
|
|
4706
|
-
overflow: hidden !important;
|
|
4707
|
-
z-index: 100000 !important;
|
|
4708
|
-
padding-top: env(safe-area-inset-top);
|
|
4709
|
-
}
|
|
4710
5063
|
.zenit-chat-panel.zenit-chat-panel--fullscreen .zenit-ai-body {
|
|
4711
5064
|
flex: 1;
|
|
4712
5065
|
min-height: 0;
|
|
@@ -4726,16 +5079,20 @@ var FloatingChatBox = ({
|
|
|
4726
5079
|
"div",
|
|
4727
5080
|
{
|
|
4728
5081
|
ref: chatBoxRef,
|
|
4729
|
-
className: `zenit-chat-panel${expanded ? " zenit-chat-panel--expanded" : ""}${isMobile ? " zenit-chat-panel--fullscreen" : ""}`,
|
|
4730
|
-
style: {
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
5082
|
+
className: `zenit-chat-panel${expanded && !isMobile ? " zenit-chat-panel--expanded" : ""}${isMobile ? " zenit-chat-panel--fullscreen" : ""}`,
|
|
5083
|
+
style: (() => {
|
|
5084
|
+
const desktopStyle = expanded ? styles.panelExpanded : styles.panelNormal;
|
|
5085
|
+
const mobileStyle = styles.panelMobileFullscreen;
|
|
5086
|
+
return {
|
|
5087
|
+
...styles.panel,
|
|
5088
|
+
...isMobile ? mobileStyle : desktopStyle
|
|
5089
|
+
};
|
|
5090
|
+
})(),
|
|
4734
5091
|
children: [
|
|
4735
5092
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("header", { style: styles.header, children: [
|
|
4736
5093
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { style: styles.title, children: "Asistente Zenit AI" }),
|
|
4737
5094
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.headerButtons, children: [
|
|
4738
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
5095
|
+
!isMobile && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4739
5096
|
"button",
|
|
4740
5097
|
{
|
|
4741
5098
|
type: "button",
|