zenit-sdk 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/{chunk-ITF7QCUZ.mjs → chunk-PCTRVN4O.mjs} +1140 -926
- package/dist/chunk-PCTRVN4O.mjs.map +1 -0
- package/dist/{index-kGwfqTc_.d.mts → index-DvcYGhqj.d.mts} +70 -4
- package/dist/{index-kGwfqTc_.d.ts → index-DvcYGhqj.d.ts} +70 -4
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1272 -937
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +119 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +1154 -940
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1 -1
- package/package.json +10 -7
- package/dist/chunk-ITF7QCUZ.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -75,12 +75,15 @@ __export(src_exports, {
|
|
|
75
75
|
getZoomOpacityFactor: () => getZoomOpacityFactor,
|
|
76
76
|
initLayerStates: () => initLayerStates,
|
|
77
77
|
isPolygonLayer: () => isPolygonLayer,
|
|
78
|
+
mergeFilters: () => mergeFilters,
|
|
78
79
|
normalizeBbox: () => normalizeBbox,
|
|
80
|
+
normalizeFilters: () => normalizeFilters,
|
|
79
81
|
normalizeMapCenter: () => normalizeMapCenter,
|
|
80
82
|
normalizeMapLayers: () => normalizeMapLayers,
|
|
81
83
|
resetOverrides: () => resetOverrides,
|
|
82
84
|
resolveLayerAccent: () => resolveLayerAccent,
|
|
83
85
|
resolveLayerStrategy: () => resolveLayerStrategy,
|
|
86
|
+
resolveRuntimeConfig: () => resolveRuntimeConfig,
|
|
84
87
|
sendMessage: () => sendMessage,
|
|
85
88
|
sendMessageStream: () => sendMessageStream,
|
|
86
89
|
shouldSkipGeojsonDownload: () => shouldSkipGeojsonDownload,
|
|
@@ -97,6 +100,12 @@ var HttpClient = class {
|
|
|
97
100
|
this.resolveTokens = options.resolveTokens;
|
|
98
101
|
this.resolveAuthorizationHeader = options.resolveAuthorizationHeader ?? (() => ({}));
|
|
99
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Update base URL at runtime (e.g. when a host injects config).
|
|
105
|
+
*/
|
|
106
|
+
setBaseUrl(baseUrl) {
|
|
107
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
108
|
+
}
|
|
100
109
|
async get(path, options = {}) {
|
|
101
110
|
const headers = {
|
|
102
111
|
...options.headers,
|
|
@@ -923,6 +932,7 @@ var ZenitClient = class {
|
|
|
923
932
|
this.accessToken = config.accessToken;
|
|
924
933
|
this.refreshToken = config.refreshToken;
|
|
925
934
|
this.sdkToken = config.sdkToken;
|
|
935
|
+
this.defaultFilters = config.defaultFilters;
|
|
926
936
|
this.httpClient = new HttpClient({
|
|
927
937
|
baseUrl: config.baseUrl,
|
|
928
938
|
resolveTokens: () => ({ accessToken: this.accessToken, sdkToken: this.sdkToken }),
|
|
@@ -958,14 +968,78 @@ var ZenitClient = class {
|
|
|
958
968
|
this.setAccessToken(token);
|
|
959
969
|
}
|
|
960
970
|
}
|
|
971
|
+
/**
|
|
972
|
+
* Update the access token at runtime.
|
|
973
|
+
*/
|
|
961
974
|
setAccessToken(token) {
|
|
962
975
|
this.accessToken = token;
|
|
963
976
|
this.config.accessToken = token;
|
|
964
977
|
}
|
|
978
|
+
/**
|
|
979
|
+
* Update the refresh token at runtime.
|
|
980
|
+
*/
|
|
965
981
|
setRefreshToken(token) {
|
|
966
982
|
this.refreshToken = token;
|
|
967
983
|
this.config.refreshToken = token;
|
|
968
984
|
}
|
|
985
|
+
/**
|
|
986
|
+
* Update the SDK token at runtime.
|
|
987
|
+
*/
|
|
988
|
+
setSdkToken(token) {
|
|
989
|
+
this.sdkToken = token;
|
|
990
|
+
this.config.sdkToken = token;
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Update both access token and SDK token at once.
|
|
994
|
+
*/
|
|
995
|
+
setAuth(params) {
|
|
996
|
+
if ("accessToken" in params) {
|
|
997
|
+
this.setAccessToken(params.accessToken);
|
|
998
|
+
}
|
|
999
|
+
if ("sdkToken" in params) {
|
|
1000
|
+
this.setSdkToken(params.sdkToken);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Update base URL at runtime (e.g. injected config from a host app).
|
|
1005
|
+
*/
|
|
1006
|
+
setBaseUrl(baseUrl) {
|
|
1007
|
+
this.config.baseUrl = baseUrl;
|
|
1008
|
+
this.httpClient.setBaseUrl(baseUrl);
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Store default filters for UI integrations.
|
|
1012
|
+
*/
|
|
1013
|
+
setDefaultFilters(filters) {
|
|
1014
|
+
this.defaultFilters = filters;
|
|
1015
|
+
this.config.defaultFilters = filters;
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Return default filters for UI integrations.
|
|
1019
|
+
*/
|
|
1020
|
+
getDefaultFilters() {
|
|
1021
|
+
return this.defaultFilters ? { ...this.defaultFilters } : void 0;
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Get a readonly snapshot of the current SDK config.
|
|
1025
|
+
*/
|
|
1026
|
+
getConfig() {
|
|
1027
|
+
return { ...this.config };
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Get a readonly snapshot of runtime config for debugging or host integrations.
|
|
1031
|
+
*/
|
|
1032
|
+
getRuntimeConfig() {
|
|
1033
|
+
return {
|
|
1034
|
+
baseUrl: this.config.baseUrl,
|
|
1035
|
+
accessToken: this.accessToken,
|
|
1036
|
+
sdkToken: this.sdkToken,
|
|
1037
|
+
defaultFilters: this.defaultFilters ? { ...this.defaultFilters } : void 0
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Build an authorization header on demand using the current token values.
|
|
1042
|
+
*/
|
|
969
1043
|
getAuthorizationHeader() {
|
|
970
1044
|
const header = {};
|
|
971
1045
|
if (this.accessToken) {
|
|
@@ -978,6 +1052,50 @@ var ZenitClient = class {
|
|
|
978
1052
|
}
|
|
979
1053
|
};
|
|
980
1054
|
|
|
1055
|
+
// src/config/ZenitRuntimeConfig.ts
|
|
1056
|
+
var isPlainRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1057
|
+
var normalizeFilters = (filters) => {
|
|
1058
|
+
if (!isPlainRecord(filters)) {
|
|
1059
|
+
return {};
|
|
1060
|
+
}
|
|
1061
|
+
return { ...filters };
|
|
1062
|
+
};
|
|
1063
|
+
var mergeFilters = (base = {}, next = {}) => ({
|
|
1064
|
+
...base,
|
|
1065
|
+
...next
|
|
1066
|
+
});
|
|
1067
|
+
var resolveRuntimeConfig = (input) => {
|
|
1068
|
+
if (!isPlainRecord(input)) {
|
|
1069
|
+
return null;
|
|
1070
|
+
}
|
|
1071
|
+
const baseUrl = typeof input.baseUrl === "string" ? input.baseUrl : null;
|
|
1072
|
+
if (!baseUrl) {
|
|
1073
|
+
return null;
|
|
1074
|
+
}
|
|
1075
|
+
const accessToken = typeof input.accessToken === "string" ? input.accessToken : void 0;
|
|
1076
|
+
const sdkToken = typeof input.sdkToken === "string" ? input.sdkToken : void 0;
|
|
1077
|
+
let mapId;
|
|
1078
|
+
if (typeof input.mapId === "number" && !Number.isNaN(input.mapId)) {
|
|
1079
|
+
mapId = input.mapId;
|
|
1080
|
+
} else if (typeof input.mapId === "string" && input.mapId.trim() !== "") {
|
|
1081
|
+
const parsed = Number(input.mapId);
|
|
1082
|
+
if (!Number.isNaN(parsed)) {
|
|
1083
|
+
mapId = parsed;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
let defaultFilters;
|
|
1087
|
+
if (isPlainRecord(input.defaultFilters)) {
|
|
1088
|
+
defaultFilters = normalizeFilters(input.defaultFilters);
|
|
1089
|
+
}
|
|
1090
|
+
return {
|
|
1091
|
+
baseUrl,
|
|
1092
|
+
accessToken,
|
|
1093
|
+
sdkToken,
|
|
1094
|
+
mapId,
|
|
1095
|
+
defaultFilters
|
|
1096
|
+
};
|
|
1097
|
+
};
|
|
1098
|
+
|
|
981
1099
|
// src/maps/helpers.ts
|
|
982
1100
|
function toNumber(value) {
|
|
983
1101
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -1403,9 +1521,9 @@ function normalizeBbox(input) {
|
|
|
1403
1521
|
}
|
|
1404
1522
|
|
|
1405
1523
|
// src/react/ZenitMap.tsx
|
|
1406
|
-
var
|
|
1407
|
-
var
|
|
1408
|
-
var
|
|
1524
|
+
var import_react4 = __toESM(require("react"));
|
|
1525
|
+
var import_react_leaflet4 = require("react-leaflet");
|
|
1526
|
+
var import_leaflet4 = __toESM(require("leaflet"));
|
|
1409
1527
|
|
|
1410
1528
|
// src/react/layerStyleHelpers.ts
|
|
1411
1529
|
function resolveLayerAccent(style) {
|
|
@@ -1427,9 +1545,9 @@ function getAccentByLayerId(layerId, mapLayers) {
|
|
|
1427
1545
|
|
|
1428
1546
|
// src/react/zoomOpacity.ts
|
|
1429
1547
|
var DEFAULT_OPTIONS = {
|
|
1430
|
-
minZoom:
|
|
1431
|
-
maxZoom:
|
|
1432
|
-
minFactor: 0.
|
|
1548
|
+
minZoom: 11,
|
|
1549
|
+
maxZoom: 15,
|
|
1550
|
+
minFactor: 0.3,
|
|
1433
1551
|
maxFactor: 1,
|
|
1434
1552
|
minOpacity: 0.1,
|
|
1435
1553
|
maxOpacity: 0.92
|
|
@@ -1466,302 +1584,215 @@ function getEffectiveLayerOpacity(baseOpacity, zoom, layerType, geometryType, op
|
|
|
1466
1584
|
return clampNumber(effective, settings.minOpacity, settings.maxOpacity);
|
|
1467
1585
|
}
|
|
1468
1586
|
|
|
1469
|
-
// src/react/
|
|
1587
|
+
// src/react/map/layer-geojson.tsx
|
|
1588
|
+
var import_react_leaflet = require("react-leaflet");
|
|
1589
|
+
var import_leaflet = __toESM(require("leaflet"));
|
|
1470
1590
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1471
|
-
var
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
if (!Array.isArray(geojson.features) || geojson.features.length === 0) return null;
|
|
1476
|
-
const coords = [];
|
|
1477
|
-
const collect = (candidate) => {
|
|
1478
|
-
if (!Array.isArray(candidate)) return;
|
|
1479
|
-
if (candidate.length === 2 && typeof candidate[0] === "number" && typeof candidate[1] === "number") {
|
|
1480
|
-
coords.push([candidate[0], candidate[1]]);
|
|
1481
|
-
return;
|
|
1482
|
-
}
|
|
1483
|
-
candidate.forEach((entry) => collect(entry));
|
|
1484
|
-
};
|
|
1485
|
-
geojson.features.forEach((feature) => {
|
|
1486
|
-
collect(feature.geometry?.coordinates);
|
|
1487
|
-
});
|
|
1488
|
-
if (coords.length === 0) return null;
|
|
1489
|
-
const [firstLon, firstLat] = coords[0];
|
|
1490
|
-
const bbox = { minLon: firstLon, minLat: firstLat, maxLon: firstLon, maxLat: firstLat };
|
|
1491
|
-
coords.forEach(([lon, lat]) => {
|
|
1492
|
-
bbox.minLon = Math.min(bbox.minLon, lon);
|
|
1493
|
-
bbox.minLat = Math.min(bbox.minLat, lat);
|
|
1494
|
-
bbox.maxLon = Math.max(bbox.maxLon, lon);
|
|
1495
|
-
bbox.maxLat = Math.max(bbox.maxLat, lat);
|
|
1496
|
-
});
|
|
1497
|
-
return bbox;
|
|
1591
|
+
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
1592
|
+
function getGeometryType(feature) {
|
|
1593
|
+
const t = feature?.geometry?.type;
|
|
1594
|
+
return typeof t === "string" ? t : null;
|
|
1498
1595
|
}
|
|
1499
|
-
function
|
|
1500
|
-
const
|
|
1501
|
-
|
|
1502
|
-
const first = valid[0];
|
|
1503
|
-
return valid.slice(1).reduce(
|
|
1504
|
-
(acc, bbox) => ({
|
|
1505
|
-
minLon: Math.min(acc.minLon, bbox.minLon),
|
|
1506
|
-
minLat: Math.min(acc.minLat, bbox.minLat),
|
|
1507
|
-
maxLon: Math.max(acc.maxLon, bbox.maxLon),
|
|
1508
|
-
maxLat: Math.max(acc.maxLat, bbox.maxLat)
|
|
1509
|
-
}),
|
|
1510
|
-
{ ...first }
|
|
1511
|
-
);
|
|
1596
|
+
function isPointGeometry(feature) {
|
|
1597
|
+
const geometryType = getGeometryType(feature);
|
|
1598
|
+
return geometryType !== null && POINT_GEOMETRY_TYPES.has(geometryType);
|
|
1512
1599
|
}
|
|
1513
|
-
function
|
|
1514
|
-
const
|
|
1515
|
-
|
|
1516
|
-
return layerId;
|
|
1600
|
+
function isNonPointGeometry(feature) {
|
|
1601
|
+
const geometryType = getGeometryType(feature);
|
|
1602
|
+
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
1517
1603
|
}
|
|
1518
|
-
function
|
|
1519
|
-
return
|
|
1604
|
+
function buildFeatureCollection(features) {
|
|
1605
|
+
return {
|
|
1606
|
+
type: "FeatureCollection",
|
|
1607
|
+
features
|
|
1608
|
+
};
|
|
1520
1609
|
}
|
|
1521
|
-
var
|
|
1522
|
-
|
|
1610
|
+
var LayerGeoJson = ({
|
|
1611
|
+
layerId,
|
|
1612
|
+
data,
|
|
1613
|
+
baseOpacity,
|
|
1614
|
+
isMobile,
|
|
1615
|
+
panesReady,
|
|
1616
|
+
mapInstance,
|
|
1617
|
+
fillPaneName,
|
|
1618
|
+
pointsPaneName,
|
|
1619
|
+
layerType,
|
|
1620
|
+
styleFn,
|
|
1621
|
+
onEachFeature,
|
|
1622
|
+
onPolygonLabel
|
|
1623
|
+
}) => {
|
|
1624
|
+
const features = data.features ?? [];
|
|
1625
|
+
const fillFeatures = features.filter(isNonPointGeometry);
|
|
1626
|
+
const pointFeatures = features.filter(isPointGeometry);
|
|
1627
|
+
const fillData = fillFeatures.length > 0 ? buildFeatureCollection(fillFeatures) : null;
|
|
1628
|
+
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
1629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1630
|
+
fillData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1631
|
+
import_react_leaflet.GeoJSON,
|
|
1632
|
+
{
|
|
1633
|
+
data: fillData,
|
|
1634
|
+
pane: panesReady && mapInstance?.getPane(fillPaneName) ? fillPaneName : void 0,
|
|
1635
|
+
style: (feature) => styleFn(feature, layerType, baseOpacity),
|
|
1636
|
+
onEachFeature: (feature, layer) => {
|
|
1637
|
+
onEachFeature(feature, layer);
|
|
1638
|
+
onPolygonLabel?.(feature, layer);
|
|
1639
|
+
}
|
|
1640
|
+
},
|
|
1641
|
+
`fill-${layerId}`
|
|
1642
|
+
),
|
|
1643
|
+
pointsData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1644
|
+
import_react_leaflet.GeoJSON,
|
|
1645
|
+
{
|
|
1646
|
+
data: pointsData,
|
|
1647
|
+
pane: panesReady && mapInstance?.getPane(pointsPaneName) ? pointsPaneName : void 0,
|
|
1648
|
+
pointToLayer: (feature, latlng) => import_leaflet.default.circleMarker(latlng, {
|
|
1649
|
+
radius: isMobile ? 8 : 6,
|
|
1650
|
+
...styleFn(feature, layerType, baseOpacity)
|
|
1651
|
+
}),
|
|
1652
|
+
onEachFeature
|
|
1653
|
+
},
|
|
1654
|
+
`points-${layerId}`
|
|
1655
|
+
)
|
|
1656
|
+
] });
|
|
1657
|
+
};
|
|
1658
|
+
|
|
1659
|
+
// src/react/map/location-control.tsx
|
|
1660
|
+
var import_react2 = require("react");
|
|
1661
|
+
var import_react_dom = require("react-dom");
|
|
1662
|
+
var import_react_leaflet2 = require("react-leaflet");
|
|
1663
|
+
var import_leaflet3 = __toESM(require("leaflet"));
|
|
1664
|
+
|
|
1665
|
+
// src/react/hooks/use-geolocation.ts
|
|
1666
|
+
var import_react = require("react");
|
|
1667
|
+
function useGeolocation(options) {
|
|
1668
|
+
const [isTracking, setIsTracking] = (0, import_react.useState)(false);
|
|
1669
|
+
const [location, setLocation] = (0, import_react.useState)(null);
|
|
1670
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
1671
|
+
const watchIdRef = (0, import_react.useRef)(null);
|
|
1672
|
+
const stopTracking = (0, import_react.useCallback)(() => {
|
|
1673
|
+
if (watchIdRef.current !== null && typeof navigator !== "undefined" && navigator.geolocation) {
|
|
1674
|
+
navigator.geolocation.clearWatch(watchIdRef.current);
|
|
1675
|
+
}
|
|
1676
|
+
watchIdRef.current = null;
|
|
1677
|
+
setIsTracking(false);
|
|
1678
|
+
}, []);
|
|
1679
|
+
const startTracking = (0, import_react.useCallback)(() => {
|
|
1680
|
+
if (typeof navigator === "undefined" || !navigator.geolocation) {
|
|
1681
|
+
setError({ code: 0, message: "La geolocalizaci\xF3n no est\xE1 disponible en este navegador." });
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
setError(null);
|
|
1685
|
+
watchIdRef.current = navigator.geolocation.watchPosition(
|
|
1686
|
+
(position) => {
|
|
1687
|
+
setLocation({
|
|
1688
|
+
lat: position.coords.latitude,
|
|
1689
|
+
lon: position.coords.longitude,
|
|
1690
|
+
accuracy: position.coords.accuracy
|
|
1691
|
+
});
|
|
1692
|
+
setIsTracking(true);
|
|
1693
|
+
},
|
|
1694
|
+
(err) => {
|
|
1695
|
+
setError({ code: err.code, message: err.message });
|
|
1696
|
+
stopTracking();
|
|
1697
|
+
},
|
|
1698
|
+
{
|
|
1699
|
+
enableHighAccuracy: options?.enableHighAccuracy ?? true,
|
|
1700
|
+
timeout: options?.timeout ?? 12e3,
|
|
1701
|
+
maximumAge: options?.maximumAge ?? 0
|
|
1702
|
+
}
|
|
1703
|
+
);
|
|
1704
|
+
}, [options?.enableHighAccuracy, options?.maximumAge, options?.timeout, stopTracking]);
|
|
1705
|
+
const toggleTracking = (0, import_react.useCallback)(() => {
|
|
1706
|
+
if (isTracking) {
|
|
1707
|
+
stopTracking();
|
|
1708
|
+
} else {
|
|
1709
|
+
startTracking();
|
|
1710
|
+
}
|
|
1711
|
+
}, [isTracking, startTracking, stopTracking]);
|
|
1712
|
+
const clearError = (0, import_react.useCallback)(() => setError(null), []);
|
|
1713
|
+
(0, import_react.useEffect)(() => {
|
|
1714
|
+
return () => {
|
|
1715
|
+
stopTracking();
|
|
1716
|
+
};
|
|
1717
|
+
}, [stopTracking]);
|
|
1718
|
+
return {
|
|
1719
|
+
isTracking,
|
|
1720
|
+
location,
|
|
1721
|
+
error,
|
|
1722
|
+
startTracking,
|
|
1723
|
+
stopTracking,
|
|
1724
|
+
toggleTracking,
|
|
1725
|
+
clearError
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
// src/react/map/map-utils.ts
|
|
1730
|
+
var import_leaflet2 = __toESM(require("leaflet"));
|
|
1523
1731
|
var POPUP_STYLE_ID = "zenit-leaflet-popup-styles";
|
|
1524
|
-
var
|
|
1525
|
-
var
|
|
1732
|
+
var POPUP_EXCLUDED_KEYS = /* @__PURE__ */ new Set(["geom", "geometry", "_private"]);
|
|
1733
|
+
var POPUP_HEADER_KEYS = ["nombre", "name", "title", "titulo"];
|
|
1734
|
+
var DESKTOP_POPUP_DIMENSIONS = { maxWidth: 360, minWidth: 280, maxHeight: 520 };
|
|
1735
|
+
var MOBILE_POPUP_DIMENSIONS = { maxWidth: 300, minWidth: 240, maxHeight: 420 };
|
|
1526
1736
|
var ZENIT_LEAFLET_POPUP_STYLES = `
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
/* Main popup wrapper */
|
|
1530
|
-
.zenit-leaflet-popup .leaflet-popup-content-wrapper {
|
|
1737
|
+
.custom-leaflet-popup .leaflet-popup-content-wrapper {
|
|
1531
1738
|
border-radius: 12px;
|
|
1532
|
-
box-shadow:
|
|
1533
|
-
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
1534
|
-
0 2px 4px -2px rgba(0, 0, 0, 0.1),
|
|
1535
|
-
0 0 0 1px rgba(0, 0, 0, 0.05);
|
|
1536
1739
|
padding: 0;
|
|
1537
1740
|
background: #ffffff;
|
|
1538
|
-
|
|
1741
|
+
box-shadow: 0 12px 24px rgba(15, 23, 42, 0.18);
|
|
1742
|
+
border: 1px solid rgba(15, 23, 42, 0.08);
|
|
1539
1743
|
}
|
|
1540
1744
|
|
|
1541
|
-
|
|
1542
|
-
.zenit-leaflet-popup .leaflet-popup-content {
|
|
1745
|
+
.custom-leaflet-popup .leaflet-popup-content {
|
|
1543
1746
|
margin: 0;
|
|
1544
|
-
padding:
|
|
1747
|
+
padding: 12px 14px;
|
|
1545
1748
|
font-size: 13px;
|
|
1546
|
-
line-height: 1.5;
|
|
1547
|
-
color: #374151;
|
|
1548
|
-
min-width: 100%;
|
|
1549
|
-
overflow-y: auto;
|
|
1550
|
-
overflow-x: hidden;
|
|
1551
|
-
scrollbar-width: thin;
|
|
1552
|
-
scrollbar-color: rgba(156, 163, 175, 0.5) transparent;
|
|
1553
|
-
}
|
|
1554
|
-
|
|
1555
|
-
/* Popup tip/arrow shadow */
|
|
1556
|
-
.zenit-leaflet-popup .leaflet-popup-tip-container {
|
|
1557
|
-
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
.zenit-leaflet-popup .leaflet-popup-tip {
|
|
1561
|
-
background: #ffffff;
|
|
1562
|
-
box-shadow: none;
|
|
1563
|
-
}
|
|
1564
|
-
|
|
1565
|
-
/* Close button styling */
|
|
1566
|
-
.zenit-leaflet-popup .leaflet-popup-close-button {
|
|
1567
|
-
color: #9ca3af;
|
|
1568
|
-
font-size: 18px;
|
|
1569
|
-
font-weight: 400;
|
|
1570
|
-
width: 28px;
|
|
1571
|
-
height: 28px;
|
|
1572
|
-
padding: 0;
|
|
1573
|
-
margin: 8px 8px 0 0;
|
|
1574
|
-
display: flex;
|
|
1575
|
-
align-items: center;
|
|
1576
|
-
justify-content: center;
|
|
1577
|
-
border-radius: 6px;
|
|
1578
|
-
transition: all 0.15s ease;
|
|
1579
|
-
z-index: 10;
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
.zenit-leaflet-popup .leaflet-popup-close-button:hover {
|
|
1583
|
-
color: #374151;
|
|
1584
|
-
background-color: #f3f4f6;
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
.zenit-leaflet-popup .leaflet-popup-close-button:active {
|
|
1588
|
-
background-color: #e5e7eb;
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
/* Main card container */
|
|
1592
|
-
.zenit-popup-card {
|
|
1593
|
-
display: flex;
|
|
1594
|
-
flex-direction: column;
|
|
1595
|
-
gap: 0;
|
|
1596
|
-
padding: 16px;
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
|
-
/* Individual row styling with subtle separator */
|
|
1600
|
-
.zenit-popup-row {
|
|
1601
|
-
display: flex;
|
|
1602
|
-
flex-direction: column;
|
|
1603
|
-
gap: 2px;
|
|
1604
|
-
padding: 10px 0;
|
|
1605
|
-
border-bottom: 1px solid #f3f4f6;
|
|
1606
|
-
}
|
|
1607
|
-
|
|
1608
|
-
.zenit-popup-row:first-child {
|
|
1609
|
-
padding-top: 0;
|
|
1610
|
-
}
|
|
1611
|
-
|
|
1612
|
-
.zenit-popup-row:last-child {
|
|
1613
|
-
border-bottom: none;
|
|
1614
|
-
padding-bottom: 0;
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
/* Label styling - small, gray, uppercase */
|
|
1618
|
-
.zenit-popup-label {
|
|
1619
|
-
font-size: 10px;
|
|
1620
|
-
font-weight: 500;
|
|
1621
|
-
color: #9ca3af;
|
|
1622
|
-
text-transform: uppercase;
|
|
1623
|
-
letter-spacing: 0.05em;
|
|
1624
1749
|
line-height: 1.4;
|
|
1750
|
+
color: #0f172a;
|
|
1751
|
+
max-height: min(70vh, 520px);
|
|
1752
|
+
overflow: auto;
|
|
1753
|
+
scrollbar-width: thin;
|
|
1754
|
+
scrollbar-color: rgba(148, 163, 184, 0.6) transparent;
|
|
1625
1755
|
}
|
|
1626
1756
|
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
font-size:
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
word-break: break-word;
|
|
1634
|
-
line-height: 1.5;
|
|
1635
|
-
}
|
|
1636
|
-
|
|
1637
|
-
/* Special styling for description field */
|
|
1638
|
-
.zenit-popup-row.zenit-popup-description {
|
|
1639
|
-
background-color: #f9fafb;
|
|
1640
|
-
margin: 0 -16px;
|
|
1641
|
-
padding: 12px 16px;
|
|
1642
|
-
border-bottom: 1px solid #e5e7eb;
|
|
1643
|
-
}
|
|
1644
|
-
|
|
1645
|
-
.zenit-popup-row.zenit-popup-description:first-child {
|
|
1646
|
-
margin-top: 0;
|
|
1647
|
-
border-radius: 0;
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value {
|
|
1651
|
-
font-size: 13px;
|
|
1652
|
-
line-height: 1.6;
|
|
1653
|
-
color: #374151;
|
|
1654
|
-
max-height: 150px;
|
|
1655
|
-
overflow-y: auto;
|
|
1656
|
-
padding-right: 4px;
|
|
1657
|
-
}
|
|
1658
|
-
|
|
1659
|
-
/* Preformatted text (JSON objects) */
|
|
1660
|
-
.zenit-popup-pre {
|
|
1661
|
-
margin: 0;
|
|
1662
|
-
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
1663
|
-
font-size: 11px;
|
|
1664
|
-
white-space: pre-wrap;
|
|
1665
|
-
word-break: break-word;
|
|
1666
|
-
color: #4b5563;
|
|
1667
|
-
background-color: #f9fafb;
|
|
1668
|
-
padding: 8px;
|
|
1669
|
-
border-radius: 6px;
|
|
1670
|
-
border: 1px solid #e5e7eb;
|
|
1757
|
+
.custom-leaflet-popup .leaflet-popup-close-button {
|
|
1758
|
+
color: #64748b;
|
|
1759
|
+
font-size: 16px;
|
|
1760
|
+
padding: 6px 8px;
|
|
1761
|
+
border-radius: 8px;
|
|
1762
|
+
transition: background-color 0.15s ease, color 0.15s ease;
|
|
1671
1763
|
}
|
|
1672
1764
|
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
color: #9ca3af;
|
|
1677
|
-
font-style: italic;
|
|
1678
|
-
text-align: center;
|
|
1679
|
-
padding: 20px 0;
|
|
1765
|
+
.custom-leaflet-popup .leaflet-popup-close-button:hover {
|
|
1766
|
+
color: #0f172a;
|
|
1767
|
+
background: rgba(148, 163, 184, 0.2);
|
|
1680
1768
|
}
|
|
1681
1769
|
|
|
1682
|
-
|
|
1683
|
-
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar {
|
|
1770
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar {
|
|
1684
1771
|
width: 6px;
|
|
1685
1772
|
}
|
|
1686
1773
|
|
|
1687
|
-
.
|
|
1688
|
-
background:
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb {
|
|
1692
|
-
background-color: rgba(156, 163, 175, 0.4);
|
|
1693
|
-
border-radius: 3px;
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb:hover {
|
|
1697
|
-
background-color: rgba(107, 114, 128, 0.6);
|
|
1774
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb {
|
|
1775
|
+
background: rgba(148, 163, 184, 0.5);
|
|
1776
|
+
border-radius: 999px;
|
|
1698
1777
|
}
|
|
1699
1778
|
|
|
1700
|
-
|
|
1701
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar {
|
|
1702
|
-
width: 4px;
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar-track {
|
|
1779
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-track {
|
|
1706
1780
|
background: transparent;
|
|
1707
1781
|
}
|
|
1708
1782
|
|
|
1709
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar-thumb {
|
|
1710
|
-
background-color: rgba(156, 163, 175, 0.4);
|
|
1711
|
-
border-radius: 2px;
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
|
-
/* ===== Responsive: Mobile (<640px) ===== */
|
|
1715
1783
|
@media (max-width: 640px) {
|
|
1716
|
-
.
|
|
1717
|
-
border-radius: 10px;
|
|
1718
|
-
}
|
|
1719
|
-
|
|
1720
|
-
.zenit-leaflet-popup .leaflet-popup-close-button {
|
|
1721
|
-
width: 26px;
|
|
1722
|
-
height: 26px;
|
|
1723
|
-
font-size: 16px;
|
|
1724
|
-
margin: 6px 6px 0 0;
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1727
|
-
.zenit-popup-card {
|
|
1728
|
-
padding: 12px;
|
|
1729
|
-
}
|
|
1730
|
-
|
|
1731
|
-
.zenit-popup-row {
|
|
1732
|
-
padding: 8px 0;
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1735
|
-
.zenit-popup-label {
|
|
1736
|
-
font-size: 9px;
|
|
1737
|
-
}
|
|
1738
|
-
|
|
1739
|
-
.zenit-popup-value {
|
|
1784
|
+
.custom-leaflet-popup .leaflet-popup-content {
|
|
1740
1785
|
font-size: 12px;
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
|
-
.zenit-popup-row.zenit-popup-description {
|
|
1744
|
-
margin: 0 -12px;
|
|
1745
1786
|
padding: 10px 12px;
|
|
1787
|
+
max-height: min(65vh, 420px);
|
|
1746
1788
|
}
|
|
1747
1789
|
|
|
1748
|
-
.
|
|
1749
|
-
font-size:
|
|
1750
|
-
|
|
1751
|
-
}
|
|
1752
|
-
|
|
1753
|
-
.zenit-popup-pre {
|
|
1754
|
-
font-size: 10px;
|
|
1755
|
-
padding: 6px;
|
|
1756
|
-
}
|
|
1757
|
-
|
|
1758
|
-
.zenit-popup-empty {
|
|
1759
|
-
font-size: 12px;
|
|
1760
|
-
padding: 16px 0;
|
|
1790
|
+
.custom-leaflet-popup .leaflet-popup-close-button {
|
|
1791
|
+
font-size: 14px;
|
|
1792
|
+
padding: 4px 6px;
|
|
1761
1793
|
}
|
|
1762
1794
|
}
|
|
1763
1795
|
|
|
1764
|
-
/* ===== Map tooltip styling ===== */
|
|
1765
1796
|
.zenit-map-tooltip {
|
|
1766
1797
|
background-color: rgba(31, 41, 55, 0.95);
|
|
1767
1798
|
border: none;
|
|
@@ -1776,7 +1807,23 @@ var ZENIT_LEAFLET_POPUP_STYLES = `
|
|
|
1776
1807
|
.zenit-map-tooltip::before {
|
|
1777
1808
|
border-top-color: rgba(31, 41, 55, 0.95);
|
|
1778
1809
|
}
|
|
1810
|
+
|
|
1811
|
+
.polygon-label-tooltip {
|
|
1812
|
+
background: rgba(15, 23, 42, 0.92);
|
|
1813
|
+
border: none;
|
|
1814
|
+
border-radius: 6px;
|
|
1815
|
+
color: #f8fafc;
|
|
1816
|
+
font-weight: 600;
|
|
1817
|
+
font-size: 12px;
|
|
1818
|
+
padding: 4px 8px;
|
|
1819
|
+
}
|
|
1779
1820
|
`;
|
|
1821
|
+
function clampNumber2(value, min, max) {
|
|
1822
|
+
return Math.min(max, Math.max(min, value));
|
|
1823
|
+
}
|
|
1824
|
+
function clampOpacity4(value) {
|
|
1825
|
+
return clampNumber2(value, 0, 1);
|
|
1826
|
+
}
|
|
1780
1827
|
function ensurePopupStyles() {
|
|
1781
1828
|
if (typeof document === "undefined") return;
|
|
1782
1829
|
if (document.getElementById(POPUP_STYLE_ID)) return;
|
|
@@ -1786,47 +1833,52 @@ function ensurePopupStyles() {
|
|
|
1786
1833
|
document.head.appendChild(styleTag);
|
|
1787
1834
|
}
|
|
1788
1835
|
function getPopupDimensions() {
|
|
1789
|
-
if (typeof window === "undefined"
|
|
1836
|
+
if (typeof window === "undefined") {
|
|
1790
1837
|
return DESKTOP_POPUP_DIMENSIONS;
|
|
1791
1838
|
}
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
const trimmed = value.trim();
|
|
1798
|
-
return trimmed ? trimmed : null;
|
|
1799
|
-
}
|
|
1800
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
1801
|
-
return String(value);
|
|
1802
|
-
}
|
|
1803
|
-
return null;
|
|
1839
|
+
const isSmallWidth = window.innerWidth < 640;
|
|
1840
|
+
const isShortHeight = window.innerHeight < 768;
|
|
1841
|
+
const base = isSmallWidth ? MOBILE_POPUP_DIMENSIONS : DESKTOP_POPUP_DIMENSIONS;
|
|
1842
|
+
const maxHeight = isShortHeight ? Math.min(base.maxHeight, 360) : base.maxHeight;
|
|
1843
|
+
return { ...base, maxHeight };
|
|
1804
1844
|
}
|
|
1805
|
-
function
|
|
1806
|
-
|
|
1807
|
-
const matches = Object.entries(properties).find(
|
|
1808
|
-
([key]) => DESCRIPTION_KEYS.has(key.toLowerCase())
|
|
1809
|
-
);
|
|
1810
|
-
if (!matches) return null;
|
|
1811
|
-
return normalizeDescriptionValue(matches[1]);
|
|
1845
|
+
function escapeHtml(value) {
|
|
1846
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1812
1847
|
}
|
|
1813
|
-
function
|
|
1814
|
-
|
|
1815
|
-
const json = JSON.stringify(value, null, 2);
|
|
1816
|
-
if (json !== void 0) return json;
|
|
1817
|
-
} catch {
|
|
1818
|
-
}
|
|
1819
|
-
return String(value);
|
|
1848
|
+
function formatLabel(key) {
|
|
1849
|
+
return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").trim();
|
|
1820
1850
|
}
|
|
1821
1851
|
function renderPopupValue(value) {
|
|
1822
|
-
if (value === null || value === void 0)
|
|
1823
|
-
|
|
1852
|
+
if (value === null || value === void 0) return '<span style="color:#94a3b8;">Sin datos</span>';
|
|
1853
|
+
if (value instanceof Date) {
|
|
1854
|
+
return escapeHtml(value.toLocaleDateString("es-GT"));
|
|
1855
|
+
}
|
|
1856
|
+
if (typeof value === "number") {
|
|
1857
|
+
return escapeHtml(value.toLocaleString("es-GT"));
|
|
1858
|
+
}
|
|
1859
|
+
if (typeof value === "string") {
|
|
1860
|
+
const trimmed = value.trim();
|
|
1861
|
+
if (!trimmed) return '<span style="color:#94a3b8;">Sin datos</span>';
|
|
1862
|
+
return escapeHtml(trimmed);
|
|
1824
1863
|
}
|
|
1825
1864
|
if (typeof value === "object") {
|
|
1826
|
-
|
|
1827
|
-
|
|
1865
|
+
try {
|
|
1866
|
+
return `<pre style="margin:0; white-space:pre-wrap; font-size:11px; background:#f8fafc; border:1px solid #e2e8f0; padding:6px 8px; border-radius:6px;">${escapeHtml(
|
|
1867
|
+
JSON.stringify(value, null, 2)
|
|
1868
|
+
)}</pre>`;
|
|
1869
|
+
} catch {
|
|
1870
|
+
return escapeHtml(String(value));
|
|
1871
|
+
}
|
|
1828
1872
|
}
|
|
1829
|
-
return
|
|
1873
|
+
return escapeHtml(String(value));
|
|
1874
|
+
}
|
|
1875
|
+
function extractPopupHeader(properties) {
|
|
1876
|
+
const entry = Object.entries(properties).find(([key, value]) => {
|
|
1877
|
+
if (typeof value !== "string") return false;
|
|
1878
|
+
const normalized = key.trim().toLowerCase();
|
|
1879
|
+
return POPUP_HEADER_KEYS.includes(normalized) && value.trim().length > 0;
|
|
1880
|
+
});
|
|
1881
|
+
return entry ? entry[1].trim() : null;
|
|
1830
1882
|
}
|
|
1831
1883
|
function shouldIncludePopupEntry(key, value) {
|
|
1832
1884
|
if (!key) return false;
|
|
@@ -1838,99 +1890,480 @@ function shouldIncludePopupEntry(key, value) {
|
|
|
1838
1890
|
if (typeof value === "string" && !value.trim()) return false;
|
|
1839
1891
|
return true;
|
|
1840
1892
|
}
|
|
1841
|
-
function isDescriptionKey(key) {
|
|
1842
|
-
const normalized = key.trim().toLowerCase();
|
|
1843
|
-
return DESCRIPTION_KEYS.has(normalized);
|
|
1844
|
-
}
|
|
1845
|
-
function formatLabel(key) {
|
|
1846
|
-
return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").trim();
|
|
1847
|
-
}
|
|
1848
1893
|
function createPopupContent(properties) {
|
|
1849
|
-
const
|
|
1850
|
-
|
|
1851
|
-
|
|
1894
|
+
const headerText = extractPopupHeader(properties);
|
|
1895
|
+
const entries = Object.entries(properties).filter(([key, value]) => {
|
|
1896
|
+
if (!shouldIncludePopupEntry(key, value)) return false;
|
|
1897
|
+
if (headerText && POPUP_HEADER_KEYS.includes(key.trim().toLowerCase())) return false;
|
|
1898
|
+
return true;
|
|
1899
|
+
});
|
|
1852
1900
|
if (entries.length === 0) {
|
|
1853
|
-
return
|
|
1854
|
-
}
|
|
1855
|
-
const descriptionEntry = entries.find(([key]) => isDescriptionKey(key));
|
|
1856
|
-
const otherEntries = entries.filter(([key]) => !isDescriptionKey(key));
|
|
1857
|
-
let rowsHtml = "";
|
|
1858
|
-
if (descriptionEntry) {
|
|
1859
|
-
const [key, value] = descriptionEntry;
|
|
1860
|
-
const label = escapeHtml(formatLabel(key));
|
|
1861
|
-
const valueHtml = renderPopupValue(value);
|
|
1862
|
-
rowsHtml += `
|
|
1863
|
-
<div class="zenit-popup-row zenit-popup-description">
|
|
1864
|
-
<div class="zenit-popup-label">${label}</div>
|
|
1865
|
-
<div class="zenit-popup-value">${valueHtml}</div>
|
|
1866
|
-
</div>
|
|
1867
|
-
`;
|
|
1901
|
+
return '<div style="padding:8px 0; color:#64748b; text-align:center;">Sin datos disponibles</div>';
|
|
1868
1902
|
}
|
|
1869
|
-
|
|
1903
|
+
const headerHtml = headerText ? `<div style="font-weight:700; font-size:14px; margin-bottom:8px; color:#0f172a;">${escapeHtml(
|
|
1904
|
+
headerText
|
|
1905
|
+
)}</div>` : "";
|
|
1906
|
+
const rowsHtml = entries.map(([key, value]) => {
|
|
1870
1907
|
const label = escapeHtml(formatLabel(key));
|
|
1871
1908
|
const valueHtml = renderPopupValue(value);
|
|
1872
1909
|
return `
|
|
1873
|
-
<div
|
|
1874
|
-
<div
|
|
1875
|
-
<div
|
|
1910
|
+
<div style="display:grid; grid-template-columns:minmax(90px, 35%) 1fr; gap:8px; padding:6px 0; border-bottom:1px solid #e2e8f0;">
|
|
1911
|
+
<div style="font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.04em; color:#64748b;">${label}</div>
|
|
1912
|
+
<div style="font-size:13px; color:#0f172a; word-break:break-word;">${valueHtml}</div>
|
|
1876
1913
|
</div>
|
|
1877
1914
|
`;
|
|
1878
1915
|
}).join("");
|
|
1879
|
-
return `<div
|
|
1916
|
+
return `<div>${headerHtml}${rowsHtml}</div>`;
|
|
1917
|
+
}
|
|
1918
|
+
function isPolygonType(layerType, geometryType) {
|
|
1919
|
+
const candidate = (layerType ?? geometryType ?? "").toLowerCase();
|
|
1920
|
+
return candidate === "polygon" || candidate === "multipolygon";
|
|
1921
|
+
}
|
|
1922
|
+
function calculateZoomBasedOpacity(zoom, baseOpacity, layerType, geometryType) {
|
|
1923
|
+
if (!isPolygonType(layerType, geometryType)) return clampOpacity4(baseOpacity);
|
|
1924
|
+
const minZoom = 11;
|
|
1925
|
+
const maxZoom = 15;
|
|
1926
|
+
const minFactor = 0.3;
|
|
1927
|
+
if (maxZoom <= minZoom) return clampOpacity4(baseOpacity * minFactor);
|
|
1928
|
+
const t = clampNumber2((zoom - minZoom) / (maxZoom - minZoom), 0, 1);
|
|
1929
|
+
const factor = 1 - (1 - minFactor) * t;
|
|
1930
|
+
return clampOpacity4(baseOpacity * factor);
|
|
1931
|
+
}
|
|
1932
|
+
function layerStyleToLeaflet(options) {
|
|
1933
|
+
const { baseOpacity, zoom, layerStyle, geometryType, layerType } = options;
|
|
1934
|
+
const sanitizedOpacity = clampOpacity4(baseOpacity);
|
|
1935
|
+
const zoomOpacity = calculateZoomBasedOpacity(zoom, sanitizedOpacity, layerType, geometryType);
|
|
1936
|
+
const styleFillOpacity = typeof layerStyle?.fillOpacity === "number" ? clampOpacity4(layerStyle.fillOpacity) : 0.8;
|
|
1937
|
+
return {
|
|
1938
|
+
color: layerStyle?.color ?? layerStyle?.fillColor ?? "#2563eb",
|
|
1939
|
+
weight: layerStyle?.weight ?? 2,
|
|
1940
|
+
fillColor: layerStyle?.fillColor ?? layerStyle?.color ?? "#2563eb",
|
|
1941
|
+
opacity: clampOpacity4(Math.max(0.35, zoomOpacity * 0.9)),
|
|
1942
|
+
fillOpacity: clampOpacity4(zoomOpacity * styleFillOpacity)
|
|
1943
|
+
};
|
|
1944
|
+
}
|
|
1945
|
+
function getRgbFromColor(color) {
|
|
1946
|
+
const trimmed = color.trim();
|
|
1947
|
+
if (trimmed.startsWith("#")) {
|
|
1948
|
+
const hex = trimmed.replace("#", "");
|
|
1949
|
+
const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
|
|
1950
|
+
if (expanded.length === 6) {
|
|
1951
|
+
const r = parseInt(expanded.slice(0, 2), 16);
|
|
1952
|
+
const g = parseInt(expanded.slice(2, 4), 16);
|
|
1953
|
+
const b = parseInt(expanded.slice(4, 6), 16);
|
|
1954
|
+
return { r, g, b };
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
const rgbMatch = trimmed.match(/rgba?\(([^)]+)\)/i);
|
|
1958
|
+
if (rgbMatch) {
|
|
1959
|
+
const [r, g, b] = rgbMatch[1].split(",").map((value) => parseFloat(value.trim())).slice(0, 3);
|
|
1960
|
+
if ([r, g, b].every((value) => Number.isFinite(value))) {
|
|
1961
|
+
return { r, g, b };
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
return null;
|
|
1965
|
+
}
|
|
1966
|
+
function getLabelTextStyles(color) {
|
|
1967
|
+
const rgb = getRgbFromColor(color);
|
|
1968
|
+
if (!rgb) {
|
|
1969
|
+
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.6)" };
|
|
1970
|
+
}
|
|
1971
|
+
const luminance = (0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b) / 255;
|
|
1972
|
+
if (luminance > 0.6) {
|
|
1973
|
+
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.7)" };
|
|
1974
|
+
}
|
|
1975
|
+
return { color: "#ffffff", shadow: "0 1px 2px rgba(0, 0, 0, 0.4)" };
|
|
1976
|
+
}
|
|
1977
|
+
function withAlpha(color, alpha) {
|
|
1978
|
+
const trimmed = color.trim();
|
|
1979
|
+
if (trimmed.startsWith("#")) {
|
|
1980
|
+
const hex = trimmed.replace("#", "");
|
|
1981
|
+
const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
|
|
1982
|
+
if (expanded.length === 6) {
|
|
1983
|
+
const r = parseInt(expanded.slice(0, 2), 16);
|
|
1984
|
+
const g = parseInt(expanded.slice(2, 4), 16);
|
|
1985
|
+
const b = parseInt(expanded.slice(4, 6), 16);
|
|
1986
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
if (trimmed.startsWith("rgb(")) {
|
|
1990
|
+
const inner = trimmed.slice(4, -1);
|
|
1991
|
+
return `rgba(${inner}, ${alpha})`;
|
|
1992
|
+
}
|
|
1993
|
+
if (trimmed.startsWith("rgba(")) {
|
|
1994
|
+
const inner = trimmed.slice(5, -1).split(",").slice(0, 3).map((value) => value.trim());
|
|
1995
|
+
return `rgba(${inner.join(", ")}, ${alpha})`;
|
|
1996
|
+
}
|
|
1997
|
+
return color;
|
|
1998
|
+
}
|
|
1999
|
+
function createCustomIcon(label, opacity, color) {
|
|
2000
|
+
const size = 60;
|
|
2001
|
+
const innerSize = 44;
|
|
2002
|
+
const textStyles = getLabelTextStyles(color);
|
|
2003
|
+
const safeLabel = escapeHtml(label);
|
|
2004
|
+
const clampedOpacity = Math.min(1, Math.max(0.92, opacity));
|
|
2005
|
+
const innerBackground = withAlpha(color, 0.9);
|
|
2006
|
+
return import_leaflet2.default.divIcon({
|
|
2007
|
+
className: "zenit-label-marker",
|
|
2008
|
+
iconSize: [size, size],
|
|
2009
|
+
iconAnchor: [size / 2, size / 2],
|
|
2010
|
+
html: `
|
|
2011
|
+
<div
|
|
2012
|
+
title="${safeLabel}"
|
|
2013
|
+
style="
|
|
2014
|
+
width:${size}px;
|
|
2015
|
+
height:${size}px;
|
|
2016
|
+
border-radius:9999px;
|
|
2017
|
+
background:rgba(255, 255, 255, 0.95);
|
|
2018
|
+
border:3px solid rgba(255, 255, 255, 1);
|
|
2019
|
+
display:flex;
|
|
2020
|
+
align-items:center;
|
|
2021
|
+
justify-content:center;
|
|
2022
|
+
opacity:${clampedOpacity};
|
|
2023
|
+
box-shadow:0 2px 6px rgba(0, 0, 0, 0.25);
|
|
2024
|
+
pointer-events:none;
|
|
2025
|
+
"
|
|
2026
|
+
>
|
|
2027
|
+
<div
|
|
2028
|
+
style="
|
|
2029
|
+
width:${innerSize}px;
|
|
2030
|
+
height:${innerSize}px;
|
|
2031
|
+
border-radius:9999px;
|
|
2032
|
+
background:${innerBackground};
|
|
2033
|
+
display:flex;
|
|
2034
|
+
align-items:center;
|
|
2035
|
+
justify-content:center;
|
|
2036
|
+
box-shadow:inset 0 0 0 1px rgba(15, 23, 42, 0.12);
|
|
2037
|
+
"
|
|
2038
|
+
>
|
|
2039
|
+
<span
|
|
2040
|
+
style="
|
|
2041
|
+
color:${textStyles.color};
|
|
2042
|
+
font-size:20px;
|
|
2043
|
+
font-weight:800;
|
|
2044
|
+
text-shadow:${textStyles.shadow};
|
|
2045
|
+
"
|
|
2046
|
+
>
|
|
2047
|
+
${safeLabel}
|
|
2048
|
+
</span>
|
|
2049
|
+
</div>
|
|
2050
|
+
</div>
|
|
2051
|
+
`
|
|
2052
|
+
});
|
|
2053
|
+
}
|
|
2054
|
+
function createLocationIcon() {
|
|
2055
|
+
return import_leaflet2.default.divIcon({
|
|
2056
|
+
className: "zenit-location-marker",
|
|
2057
|
+
iconSize: [18, 18],
|
|
2058
|
+
iconAnchor: [9, 9],
|
|
2059
|
+
html: `
|
|
2060
|
+
<div style="width:18px;height:18px;border-radius:9999px;background:#2563eb;border:2px solid #fff;box-shadow:0 0 0 4px rgba(37, 99, 235, 0.25);"></div>
|
|
2061
|
+
`
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
// src/react/map/location-control.tsx
|
|
2066
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2067
|
+
var LOCATION_STYLE_ID = "zenit-location-control-styles";
|
|
2068
|
+
var LOCATION_STYLES = `
|
|
2069
|
+
.zenit-location-control {
|
|
2070
|
+
display: flex;
|
|
2071
|
+
flex-direction: column;
|
|
2072
|
+
gap: 8px;
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
.zenit-location-button {
|
|
2076
|
+
width: 42px;
|
|
2077
|
+
height: 42px;
|
|
2078
|
+
border-radius: 12px;
|
|
2079
|
+
border: none;
|
|
2080
|
+
background: #ffffff;
|
|
2081
|
+
color: #0f172a;
|
|
2082
|
+
box-shadow: 0 8px 18px rgba(15, 23, 42, 0.2);
|
|
2083
|
+
display: inline-flex;
|
|
2084
|
+
align-items: center;
|
|
2085
|
+
justify-content: center;
|
|
2086
|
+
cursor: pointer;
|
|
2087
|
+
position: relative;
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
.zenit-location-button.zenit-location-button--tracking {
|
|
2091
|
+
animation: zenitLocationPulse 1.8s infinite;
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
.zenit-location-button:hover {
|
|
2095
|
+
background: #f8fafc;
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
.zenit-location-badge {
|
|
2099
|
+
position: absolute;
|
|
2100
|
+
top: -6px;
|
|
2101
|
+
right: -6px;
|
|
2102
|
+
width: 18px;
|
|
2103
|
+
height: 18px;
|
|
2104
|
+
border-radius: 999px;
|
|
2105
|
+
background: #ef4444;
|
|
2106
|
+
color: #fff;
|
|
2107
|
+
font-size: 11px;
|
|
2108
|
+
font-weight: 700;
|
|
2109
|
+
display: inline-flex;
|
|
2110
|
+
align-items: center;
|
|
2111
|
+
justify-content: center;
|
|
2112
|
+
box-shadow: 0 4px 10px rgba(239, 68, 68, 0.35);
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
.zenit-location-error {
|
|
2116
|
+
background: rgba(15, 23, 42, 0.92);
|
|
2117
|
+
color: #f8fafc;
|
|
2118
|
+
border-radius: 10px;
|
|
2119
|
+
padding: 8px 10px;
|
|
2120
|
+
font-size: 12px;
|
|
2121
|
+
max-width: 200px;
|
|
2122
|
+
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.3);
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
@keyframes zenitLocationPulse {
|
|
2126
|
+
0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.35); }
|
|
2127
|
+
70% { box-shadow: 0 0 0 12px rgba(16, 185, 129, 0); }
|
|
2128
|
+
100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
|
|
2129
|
+
}
|
|
2130
|
+
`;
|
|
2131
|
+
var LocateIcon = () => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2132
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "3" }),
|
|
2133
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "2", x2: "12", y2: "5" }),
|
|
2134
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "19", x2: "12", y2: "22" }),
|
|
2135
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "2", y1: "12", x2: "5", y2: "12" }),
|
|
2136
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "19", y1: "12", x2: "22", y2: "12" })
|
|
2137
|
+
] });
|
|
2138
|
+
var LocationControl = ({ position = "bottomleft", zoom = 16 }) => {
|
|
2139
|
+
const map = (0, import_react_leaflet2.useMap)();
|
|
2140
|
+
const controlRef = (0, import_react2.useRef)(null);
|
|
2141
|
+
const hasCenteredRef = (0, import_react2.useRef)(false);
|
|
2142
|
+
const { isTracking, location, error, toggleTracking, clearError } = useGeolocation();
|
|
2143
|
+
(0, import_react2.useEffect)(() => {
|
|
2144
|
+
if (typeof document === "undefined") return;
|
|
2145
|
+
if (document.getElementById(LOCATION_STYLE_ID)) return;
|
|
2146
|
+
const styleTag = document.createElement("style");
|
|
2147
|
+
styleTag.id = LOCATION_STYLE_ID;
|
|
2148
|
+
styleTag.textContent = LOCATION_STYLES;
|
|
2149
|
+
document.head.appendChild(styleTag);
|
|
2150
|
+
}, []);
|
|
2151
|
+
(0, import_react2.useEffect)(() => {
|
|
2152
|
+
const control = import_leaflet3.default.control({ position });
|
|
2153
|
+
control.onAdd = () => {
|
|
2154
|
+
const container = import_leaflet3.default.DomUtil.create("div", "zenit-location-control");
|
|
2155
|
+
import_leaflet3.default.DomEvent.disableClickPropagation(container);
|
|
2156
|
+
controlRef.current = container;
|
|
2157
|
+
return container;
|
|
2158
|
+
};
|
|
2159
|
+
control.addTo(map);
|
|
2160
|
+
return () => {
|
|
2161
|
+
control.remove();
|
|
2162
|
+
controlRef.current = null;
|
|
2163
|
+
};
|
|
2164
|
+
}, [map, position]);
|
|
2165
|
+
(0, import_react2.useEffect)(() => {
|
|
2166
|
+
if (!location || !isTracking) return;
|
|
2167
|
+
if (hasCenteredRef.current) return;
|
|
2168
|
+
hasCenteredRef.current = true;
|
|
2169
|
+
map.flyTo([location.lat, location.lon], zoom, { animate: true });
|
|
2170
|
+
}, [isTracking, location, map, zoom]);
|
|
2171
|
+
const markerIcon = (0, import_react2.useMemo)(() => createLocationIcon(), []);
|
|
2172
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2173
|
+
controlRef.current && (0, import_react_dom.createPortal)(
|
|
2174
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
2175
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2176
|
+
"button",
|
|
2177
|
+
{
|
|
2178
|
+
type: "button",
|
|
2179
|
+
className: `zenit-location-button${isTracking ? " zenit-location-button--tracking" : ""}`,
|
|
2180
|
+
onClick: () => {
|
|
2181
|
+
if (error) {
|
|
2182
|
+
clearError();
|
|
2183
|
+
}
|
|
2184
|
+
toggleTracking();
|
|
2185
|
+
},
|
|
2186
|
+
"aria-label": isTracking ? "Detener ubicaci\xF3n" : "Mostrar mi ubicaci\xF3n",
|
|
2187
|
+
children: [
|
|
2188
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LocateIcon, {}),
|
|
2189
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "zenit-location-badge", children: "!" })
|
|
2190
|
+
]
|
|
2191
|
+
}
|
|
2192
|
+
),
|
|
2193
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "zenit-location-error", children: error.message || "No se pudo acceder a tu ubicaci\xF3n." })
|
|
2194
|
+
] }),
|
|
2195
|
+
controlRef.current
|
|
2196
|
+
),
|
|
2197
|
+
location && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2198
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_leaflet2.Marker, { position: [location.lat, location.lon], icon: markerIcon }),
|
|
2199
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2200
|
+
import_react_leaflet2.Circle,
|
|
2201
|
+
{
|
|
2202
|
+
center: [location.lat, location.lon],
|
|
2203
|
+
radius: location.accuracy,
|
|
2204
|
+
pathOptions: { color: "#2563eb", fillColor: "#2563eb", fillOpacity: 0.15 }
|
|
2205
|
+
}
|
|
2206
|
+
)
|
|
2207
|
+
] })
|
|
2208
|
+
] });
|
|
2209
|
+
};
|
|
2210
|
+
|
|
2211
|
+
// src/react/map/map-handlers.tsx
|
|
2212
|
+
var import_react3 = require("react");
|
|
2213
|
+
var import_react_leaflet3 = require("react-leaflet");
|
|
2214
|
+
function computeBBoxFromGeojson(geojson) {
|
|
2215
|
+
if (!geojson || !Array.isArray(geojson.features)) return null;
|
|
2216
|
+
const coords = [];
|
|
2217
|
+
const collect = (candidate) => {
|
|
2218
|
+
if (!Array.isArray(candidate)) return;
|
|
2219
|
+
if (candidate.length === 2 && typeof candidate[0] === "number" && typeof candidate[1] === "number" && Number.isFinite(candidate[0]) && Number.isFinite(candidate[1])) {
|
|
2220
|
+
coords.push([candidate[0], candidate[1]]);
|
|
2221
|
+
return;
|
|
2222
|
+
}
|
|
2223
|
+
candidate.forEach((item) => collect(item));
|
|
2224
|
+
};
|
|
2225
|
+
geojson.features.forEach((feature) => {
|
|
2226
|
+
collect(feature.geometry?.coordinates);
|
|
2227
|
+
});
|
|
2228
|
+
if (coords.length === 0) return null;
|
|
2229
|
+
const [firstLon, firstLat] = coords[0];
|
|
2230
|
+
const bbox = { minLon: firstLon, minLat: firstLat, maxLon: firstLon, maxLat: firstLat };
|
|
2231
|
+
coords.forEach(([lon, lat]) => {
|
|
2232
|
+
bbox.minLon = Math.min(bbox.minLon, lon);
|
|
2233
|
+
bbox.minLat = Math.min(bbox.minLat, lat);
|
|
2234
|
+
bbox.maxLon = Math.max(bbox.maxLon, lon);
|
|
2235
|
+
bbox.maxLat = Math.max(bbox.maxLat, lat);
|
|
2236
|
+
});
|
|
2237
|
+
return bbox;
|
|
2238
|
+
}
|
|
2239
|
+
function mergeBBoxes(bboxes) {
|
|
2240
|
+
const valid = bboxes.filter((bbox) => !!bbox);
|
|
2241
|
+
if (valid.length === 0) return null;
|
|
2242
|
+
const first = valid[0];
|
|
2243
|
+
return valid.slice(1).reduce(
|
|
2244
|
+
(acc, bbox) => ({
|
|
2245
|
+
minLon: Math.min(acc.minLon, bbox.minLon),
|
|
2246
|
+
minLat: Math.min(acc.minLat, bbox.minLat),
|
|
2247
|
+
maxLon: Math.max(acc.maxLon, bbox.maxLon),
|
|
2248
|
+
maxLat: Math.max(acc.maxLat, bbox.maxLat)
|
|
2249
|
+
}),
|
|
2250
|
+
{ ...first }
|
|
2251
|
+
);
|
|
2252
|
+
}
|
|
2253
|
+
var BBoxZoomHandler = ({
|
|
2254
|
+
bbox,
|
|
2255
|
+
geojson,
|
|
2256
|
+
autoGeojson = [],
|
|
2257
|
+
enabled = true
|
|
2258
|
+
}) => {
|
|
2259
|
+
const map = (0, import_react_leaflet3.useMap)();
|
|
2260
|
+
const lastAppliedBBox = (0, import_react3.useRef)(null);
|
|
2261
|
+
const lastUserInteracted = (0, import_react3.useRef)(false);
|
|
2262
|
+
(0, import_react3.useEffect)(() => {
|
|
2263
|
+
const handleInteraction = () => {
|
|
2264
|
+
lastUserInteracted.current = true;
|
|
2265
|
+
};
|
|
2266
|
+
map.on("dragstart", handleInteraction);
|
|
2267
|
+
map.on("zoomstart", handleInteraction);
|
|
2268
|
+
return () => {
|
|
2269
|
+
map.off("dragstart", handleInteraction);
|
|
2270
|
+
map.off("zoomstart", handleInteraction);
|
|
2271
|
+
};
|
|
2272
|
+
}, [map]);
|
|
2273
|
+
(0, import_react3.useEffect)(() => {
|
|
2274
|
+
if (!enabled) return;
|
|
2275
|
+
let resolvedBBox = bbox ?? null;
|
|
2276
|
+
if (!resolvedBBox && geojson) {
|
|
2277
|
+
resolvedBBox = computeBBoxFromGeojson(geojson);
|
|
2278
|
+
}
|
|
2279
|
+
if (!resolvedBBox && autoGeojson.length > 0) {
|
|
2280
|
+
const bboxes = autoGeojson.map((collection) => computeBBoxFromGeojson(collection));
|
|
2281
|
+
resolvedBBox = mergeBBoxes(bboxes);
|
|
2282
|
+
}
|
|
2283
|
+
if (!resolvedBBox) return;
|
|
2284
|
+
const serialized = JSON.stringify(resolvedBBox);
|
|
2285
|
+
if (lastAppliedBBox.current === serialized) return;
|
|
2286
|
+
if (lastUserInteracted.current && !bbox && !geojson) {
|
|
2287
|
+
lastUserInteracted.current = false;
|
|
2288
|
+
return;
|
|
2289
|
+
}
|
|
2290
|
+
const bounds = [
|
|
2291
|
+
[resolvedBBox.minLat, resolvedBBox.minLon],
|
|
2292
|
+
[resolvedBBox.maxLat, resolvedBBox.maxLon]
|
|
2293
|
+
];
|
|
2294
|
+
map.fitBounds(bounds, { padding: [12, 12] });
|
|
2295
|
+
lastAppliedBBox.current = serialized;
|
|
2296
|
+
}, [autoGeojson, bbox, enabled, geojson, map]);
|
|
2297
|
+
return null;
|
|
2298
|
+
};
|
|
2299
|
+
var ZoomBasedOpacityHandler = ({ onZoomChange }) => {
|
|
2300
|
+
const map = (0, import_react_leaflet3.useMap)();
|
|
2301
|
+
(0, import_react3.useEffect)(() => {
|
|
2302
|
+
const handleZoom = () => {
|
|
2303
|
+
onZoomChange(map.getZoom());
|
|
2304
|
+
};
|
|
2305
|
+
map.on("zoomend", handleZoom);
|
|
2306
|
+
handleZoom();
|
|
2307
|
+
return () => {
|
|
2308
|
+
map.off("zoomend", handleZoom);
|
|
2309
|
+
};
|
|
2310
|
+
}, [map, onZoomChange]);
|
|
2311
|
+
return null;
|
|
2312
|
+
};
|
|
2313
|
+
var MapInstanceBridge = ({ onReady }) => {
|
|
2314
|
+
const map = (0, import_react_leaflet3.useMap)();
|
|
2315
|
+
(0, import_react3.useEffect)(() => {
|
|
2316
|
+
onReady(map);
|
|
2317
|
+
}, [map, onReady]);
|
|
2318
|
+
return null;
|
|
2319
|
+
};
|
|
2320
|
+
|
|
2321
|
+
// src/react/ZenitMap.tsx
|
|
2322
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
2323
|
+
var DEFAULT_CENTER = [0, 0];
|
|
2324
|
+
var DEFAULT_ZOOM = 3;
|
|
2325
|
+
var LABELS_PANE_NAME = "zenit-labels-pane";
|
|
2326
|
+
function isRecord(value) {
|
|
2327
|
+
return typeof value === "object" && value !== null;
|
|
1880
2328
|
}
|
|
1881
|
-
function
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
}
|
|
1893
|
-
if (trimmed.startsWith("rgb(")) {
|
|
1894
|
-
const inner = trimmed.slice(4, -1);
|
|
1895
|
-
return `rgba(${inner}, ${alpha})`;
|
|
1896
|
-
}
|
|
1897
|
-
if (trimmed.startsWith("rgba(")) {
|
|
1898
|
-
const inner = trimmed.slice(5, -1).split(",").slice(0, 3).map((value) => value.trim());
|
|
1899
|
-
return `rgba(${inner.join(", ")}, ${alpha})`;
|
|
2329
|
+
function isGeoJsonFeatureCollection(value) {
|
|
2330
|
+
if (!isRecord(value)) return false;
|
|
2331
|
+
const features = value.features;
|
|
2332
|
+
if (!Array.isArray(features)) return false;
|
|
2333
|
+
const type = value.type;
|
|
2334
|
+
return type === void 0 || type === "FeatureCollection";
|
|
2335
|
+
}
|
|
2336
|
+
function extractGeoJsonFeatureCollection(value) {
|
|
2337
|
+
if (isRecord(value) && "data" in value) {
|
|
2338
|
+
const data = value.data;
|
|
2339
|
+
return isGeoJsonFeatureCollection(data) ? data : null;
|
|
1900
2340
|
}
|
|
1901
|
-
return
|
|
2341
|
+
return isGeoJsonFeatureCollection(value) ? value : null;
|
|
1902
2342
|
}
|
|
1903
|
-
function
|
|
1904
|
-
const
|
|
1905
|
-
if (
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
2343
|
+
function getFeatureLayerId(feature) {
|
|
2344
|
+
const layerId = feature?.properties?.__zenit_layerId ?? feature?.properties?.layerId ?? feature?.properties?.layer_id;
|
|
2345
|
+
if (layerId === void 0 || layerId === null) return null;
|
|
2346
|
+
return layerId;
|
|
2347
|
+
}
|
|
2348
|
+
var DESCRIPTION_KEYS = /* @__PURE__ */ new Set(["descripcion", "description"]);
|
|
2349
|
+
function normalizeDescriptionValue(value) {
|
|
2350
|
+
if (value === void 0 || value === null) return null;
|
|
2351
|
+
if (typeof value === "string") {
|
|
2352
|
+
const trimmed = value.trim();
|
|
2353
|
+
return trimmed ? trimmed : null;
|
|
1914
2354
|
}
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
const [r, g, b] = rgbMatch[1].split(",").map((value) => parseFloat(value.trim())).slice(0, 3);
|
|
1918
|
-
if ([r, g, b].every((value) => Number.isFinite(value))) {
|
|
1919
|
-
return { r, g, b };
|
|
1920
|
-
}
|
|
2355
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
2356
|
+
return String(value);
|
|
1921
2357
|
}
|
|
1922
2358
|
return null;
|
|
1923
2359
|
}
|
|
1924
|
-
function
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.7)" };
|
|
1932
|
-
}
|
|
1933
|
-
return { color: "#ffffff", shadow: "0 1px 2px rgba(0, 0, 0, 0.4)" };
|
|
2360
|
+
function extractDescriptionValue(properties) {
|
|
2361
|
+
if (!properties) return null;
|
|
2362
|
+
const matches = Object.entries(properties).find(
|
|
2363
|
+
([key]) => DESCRIPTION_KEYS.has(key.toLowerCase())
|
|
2364
|
+
);
|
|
2365
|
+
if (!matches) return null;
|
|
2366
|
+
return normalizeDescriptionValue(matches[1]);
|
|
1934
2367
|
}
|
|
1935
2368
|
function getFeatureStyleOverrides(feature) {
|
|
1936
2369
|
const candidate = feature?.properties?._style;
|
|
@@ -1949,25 +2382,6 @@ function buildFeaturePopupHtml(feature) {
|
|
|
1949
2382
|
const rendered = createPopupContent(properties);
|
|
1950
2383
|
return rendered ? rendered : null;
|
|
1951
2384
|
}
|
|
1952
|
-
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
1953
|
-
function getGeometryType(feature) {
|
|
1954
|
-
const t = feature?.geometry?.type;
|
|
1955
|
-
return typeof t === "string" ? t : null;
|
|
1956
|
-
}
|
|
1957
|
-
function isPointGeometry(feature) {
|
|
1958
|
-
const geometryType = getGeometryType(feature);
|
|
1959
|
-
return geometryType !== null && POINT_GEOMETRY_TYPES.has(geometryType);
|
|
1960
|
-
}
|
|
1961
|
-
function isNonPointGeometry(feature) {
|
|
1962
|
-
const geometryType = getGeometryType(feature);
|
|
1963
|
-
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
1964
|
-
}
|
|
1965
|
-
function buildFeatureCollection(features) {
|
|
1966
|
-
return {
|
|
1967
|
-
type: "FeatureCollection",
|
|
1968
|
-
features
|
|
1969
|
-
};
|
|
1970
|
-
}
|
|
1971
2385
|
function pickIntersectFeature(baseFeature, candidates) {
|
|
1972
2386
|
if (!Array.isArray(candidates) || candidates.length === 0) return null;
|
|
1973
2387
|
const baseId = baseFeature?.id;
|
|
@@ -1994,81 +2408,7 @@ function normalizeCenterTuple(center) {
|
|
|
1994
2408
|
}
|
|
1995
2409
|
return null;
|
|
1996
2410
|
}
|
|
1997
|
-
var
|
|
1998
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
1999
|
-
const lastAppliedBBox = (0, import_react.useRef)(null);
|
|
2000
|
-
(0, import_react.useEffect)(() => {
|
|
2001
|
-
const targetBBox = bbox;
|
|
2002
|
-
if (!targetBBox) return;
|
|
2003
|
-
const serialized = JSON.stringify(targetBBox);
|
|
2004
|
-
if (lastAppliedBBox.current === serialized) return;
|
|
2005
|
-
const bounds = [
|
|
2006
|
-
[targetBBox.minLat, targetBBox.minLon],
|
|
2007
|
-
[targetBBox.maxLat, targetBBox.maxLon]
|
|
2008
|
-
];
|
|
2009
|
-
mapInstance.fitBounds(bounds, { padding: [12, 12] });
|
|
2010
|
-
lastAppliedBBox.current = serialized;
|
|
2011
|
-
}, [bbox, mapInstance]);
|
|
2012
|
-
return null;
|
|
2013
|
-
};
|
|
2014
|
-
var AutoFitToBounds = ({
|
|
2015
|
-
bbox,
|
|
2016
|
-
enabled = true
|
|
2017
|
-
}) => {
|
|
2018
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
2019
|
-
const lastAutoBBoxApplied = (0, import_react.useRef)(null);
|
|
2020
|
-
const lastUserInteracted = (0, import_react.useRef)(false);
|
|
2021
|
-
(0, import_react.useEffect)(() => {
|
|
2022
|
-
if (!enabled) return;
|
|
2023
|
-
const handleInteraction = () => {
|
|
2024
|
-
lastUserInteracted.current = true;
|
|
2025
|
-
};
|
|
2026
|
-
mapInstance.on("dragstart", handleInteraction);
|
|
2027
|
-
mapInstance.on("zoomstart", handleInteraction);
|
|
2028
|
-
return () => {
|
|
2029
|
-
mapInstance.off("dragstart", handleInteraction);
|
|
2030
|
-
mapInstance.off("zoomstart", handleInteraction);
|
|
2031
|
-
};
|
|
2032
|
-
}, [enabled, mapInstance]);
|
|
2033
|
-
(0, import_react.useEffect)(() => {
|
|
2034
|
-
if (!enabled) return;
|
|
2035
|
-
if (!bbox) return;
|
|
2036
|
-
const serialized = JSON.stringify(bbox);
|
|
2037
|
-
if (lastAutoBBoxApplied.current === serialized) return;
|
|
2038
|
-
if (lastUserInteracted.current) {
|
|
2039
|
-
lastUserInteracted.current = false;
|
|
2040
|
-
}
|
|
2041
|
-
const bounds = [
|
|
2042
|
-
[bbox.minLat, bbox.minLon],
|
|
2043
|
-
[bbox.maxLat, bbox.maxLon]
|
|
2044
|
-
];
|
|
2045
|
-
mapInstance.fitBounds(bounds, { padding: [12, 12] });
|
|
2046
|
-
lastAutoBBoxApplied.current = serialized;
|
|
2047
|
-
}, [bbox, enabled, mapInstance]);
|
|
2048
|
-
return null;
|
|
2049
|
-
};
|
|
2050
|
-
var ZoomBasedOpacityHandler = ({ onZoomChange }) => {
|
|
2051
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
2052
|
-
(0, import_react.useEffect)(() => {
|
|
2053
|
-
const handleZoom = () => {
|
|
2054
|
-
onZoomChange(mapInstance.getZoom());
|
|
2055
|
-
};
|
|
2056
|
-
mapInstance.on("zoomend", handleZoom);
|
|
2057
|
-
handleZoom();
|
|
2058
|
-
return () => {
|
|
2059
|
-
mapInstance.off("zoomend", handleZoom);
|
|
2060
|
-
};
|
|
2061
|
-
}, [mapInstance, onZoomChange]);
|
|
2062
|
-
return null;
|
|
2063
|
-
};
|
|
2064
|
-
var MapInstanceBridge = ({ onReady }) => {
|
|
2065
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
2066
|
-
(0, import_react.useEffect)(() => {
|
|
2067
|
-
onReady(mapInstance);
|
|
2068
|
-
}, [mapInstance, onReady]);
|
|
2069
|
-
return null;
|
|
2070
|
-
};
|
|
2071
|
-
var ZenitMap = (0, import_react.forwardRef)(({
|
|
2411
|
+
var ZenitMap = (0, import_react4.forwardRef)(({
|
|
2072
2412
|
client,
|
|
2073
2413
|
mapId,
|
|
2074
2414
|
height = "500px",
|
|
@@ -2093,20 +2433,21 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2093
2433
|
onZoomChange,
|
|
2094
2434
|
onMapReady
|
|
2095
2435
|
}, ref) => {
|
|
2096
|
-
const [map, setMap] = (0,
|
|
2097
|
-
const [layers, setLayers] = (0,
|
|
2098
|
-
const [effectiveStates, setEffectiveStates] = (0,
|
|
2099
|
-
const [loadingMap, setLoadingMap] = (0,
|
|
2100
|
-
const [mapError, setMapError] = (0,
|
|
2101
|
-
const [mapInstance, setMapInstance] = (0,
|
|
2102
|
-
const [panesReady, setPanesReady] = (0,
|
|
2103
|
-
const [currentZoom, setCurrentZoom] = (0,
|
|
2104
|
-
const [
|
|
2436
|
+
const [map, setMap] = (0, import_react4.useState)(null);
|
|
2437
|
+
const [layers, setLayers] = (0, import_react4.useState)([]);
|
|
2438
|
+
const [effectiveStates, setEffectiveStates] = (0, import_react4.useState)([]);
|
|
2439
|
+
const [loadingMap, setLoadingMap] = (0, import_react4.useState)(false);
|
|
2440
|
+
const [mapError, setMapError] = (0, import_react4.useState)(null);
|
|
2441
|
+
const [mapInstance, setMapInstance] = (0, import_react4.useState)(null);
|
|
2442
|
+
const [panesReady, setPanesReady] = (0, import_react4.useState)(false);
|
|
2443
|
+
const [currentZoom, setCurrentZoom] = (0, import_react4.useState)(initialZoom ?? DEFAULT_ZOOM);
|
|
2444
|
+
const [isPopupOpen, setIsPopupOpen] = (0, import_react4.useState)(false);
|
|
2445
|
+
const [isMobile, setIsMobile] = (0, import_react4.useState)(() => {
|
|
2105
2446
|
if (typeof window === "undefined") return false;
|
|
2106
2447
|
return window.matchMedia("(max-width: 768px)").matches;
|
|
2107
2448
|
});
|
|
2108
|
-
const normalizedLayers = (0,
|
|
2109
|
-
(0,
|
|
2449
|
+
const normalizedLayers = (0, import_react4.useMemo)(() => normalizeMapLayers(map), [map]);
|
|
2450
|
+
(0, import_react4.useEffect)(() => {
|
|
2110
2451
|
if (typeof window === "undefined") return;
|
|
2111
2452
|
const mql = window.matchMedia("(max-width: 768px)");
|
|
2112
2453
|
const onChange = (e) => {
|
|
@@ -2124,12 +2465,37 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2124
2465
|
}
|
|
2125
2466
|
return;
|
|
2126
2467
|
}, []);
|
|
2127
|
-
(0,
|
|
2468
|
+
(0, import_react4.useEffect)(() => {
|
|
2128
2469
|
if (featureInfoMode === "popup") {
|
|
2129
2470
|
ensurePopupStyles();
|
|
2130
2471
|
}
|
|
2131
2472
|
}, [featureInfoMode]);
|
|
2132
|
-
|
|
2473
|
+
(0, import_react4.useEffect)(() => {
|
|
2474
|
+
if (featureInfoMode !== "popup") {
|
|
2475
|
+
setIsPopupOpen(false);
|
|
2476
|
+
}
|
|
2477
|
+
}, [featureInfoMode]);
|
|
2478
|
+
(0, import_react4.useEffect)(() => {
|
|
2479
|
+
if (!mapInstance) return;
|
|
2480
|
+
const popupPane = mapInstance.getPane("popupPane");
|
|
2481
|
+
if (popupPane) {
|
|
2482
|
+
popupPane.style.zIndex = "800";
|
|
2483
|
+
}
|
|
2484
|
+
const labelsPane = mapInstance.getPane(LABELS_PANE_NAME) ?? mapInstance.createPane(LABELS_PANE_NAME);
|
|
2485
|
+
labelsPane.style.zIndex = "600";
|
|
2486
|
+
}, [mapInstance]);
|
|
2487
|
+
(0, import_react4.useEffect)(() => {
|
|
2488
|
+
if (!mapInstance) return;
|
|
2489
|
+
const handlePopupOpen = () => setIsPopupOpen(true);
|
|
2490
|
+
const handlePopupClose = () => setIsPopupOpen(false);
|
|
2491
|
+
mapInstance.on("popupopen", handlePopupOpen);
|
|
2492
|
+
mapInstance.on("popupclose", handlePopupClose);
|
|
2493
|
+
return () => {
|
|
2494
|
+
mapInstance.off("popupopen", handlePopupOpen);
|
|
2495
|
+
mapInstance.off("popupclose", handlePopupClose);
|
|
2496
|
+
};
|
|
2497
|
+
}, [mapInstance]);
|
|
2498
|
+
const layerStyleIndex = (0, import_react4.useMemo)(() => {
|
|
2133
2499
|
const index = /* @__PURE__ */ new Map();
|
|
2134
2500
|
(map?.mapLayers ?? []).forEach((entry) => {
|
|
2135
2501
|
const layerStyle = entry.layer?.style ?? entry.mapLayer?.layer?.style ?? entry.style ?? null;
|
|
@@ -2140,7 +2506,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2140
2506
|
});
|
|
2141
2507
|
return index;
|
|
2142
2508
|
}, [map]);
|
|
2143
|
-
const labelKeyIndex = (0,
|
|
2509
|
+
const labelKeyIndex = (0, import_react4.useMemo)(() => {
|
|
2144
2510
|
const index = /* @__PURE__ */ new Map();
|
|
2145
2511
|
normalizedLayers.forEach((entry) => {
|
|
2146
2512
|
const label = entry.layer?.label ?? entry.mapLayer?.label ?? entry.mapLayer.layerConfig?.label;
|
|
@@ -2150,7 +2516,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2150
2516
|
});
|
|
2151
2517
|
return index;
|
|
2152
2518
|
}, [normalizedLayers]);
|
|
2153
|
-
const layerMetaIndex = (0,
|
|
2519
|
+
const layerMetaIndex = (0, import_react4.useMemo)(() => {
|
|
2154
2520
|
const index = /* @__PURE__ */ new Map();
|
|
2155
2521
|
normalizedLayers.forEach((entry) => {
|
|
2156
2522
|
index.set(String(entry.layerId), {
|
|
@@ -2160,7 +2526,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2160
2526
|
});
|
|
2161
2527
|
return index;
|
|
2162
2528
|
}, [normalizedLayers]);
|
|
2163
|
-
const overlayStyleFunction = (0,
|
|
2529
|
+
const overlayStyleFunction = (0, import_react4.useMemo)(() => {
|
|
2164
2530
|
return (feature) => {
|
|
2165
2531
|
const featureLayerId = getFeatureLayerId(feature);
|
|
2166
2532
|
const featureStyleOverrides = getFeatureStyleOverrides(feature);
|
|
@@ -2179,11 +2545,15 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2179
2545
|
return defaultOptions;
|
|
2180
2546
|
};
|
|
2181
2547
|
}, [layerStyleIndex, mapLayers, overlayStyle]);
|
|
2182
|
-
const
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
(0,
|
|
2548
|
+
const overlayStyleFn = (0, import_react4.useCallback)(
|
|
2549
|
+
(feature, _layerType, _baseOpacity) => overlayStyleFunction(feature),
|
|
2550
|
+
[overlayStyleFunction]
|
|
2551
|
+
);
|
|
2552
|
+
const [baseStates, setBaseStates] = (0, import_react4.useState)([]);
|
|
2553
|
+
const [mapOverrides, setMapOverrides] = (0, import_react4.useState)([]);
|
|
2554
|
+
const [controlOverrides, setControlOverrides] = (0, import_react4.useState)([]);
|
|
2555
|
+
const [uiOverrides, setUiOverrides] = (0, import_react4.useState)([]);
|
|
2556
|
+
(0, import_react4.useEffect)(() => {
|
|
2187
2557
|
let isMounted = true;
|
|
2188
2558
|
setLoadingMap(true);
|
|
2189
2559
|
setMapError(null);
|
|
@@ -2206,7 +2576,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2206
2576
|
isMounted = false;
|
|
2207
2577
|
};
|
|
2208
2578
|
}, [client.maps, mapId, onError, onLoadingChange]);
|
|
2209
|
-
(0,
|
|
2579
|
+
(0, import_react4.useEffect)(() => {
|
|
2210
2580
|
if (normalizedLayers.length === 0) {
|
|
2211
2581
|
setLayers([]);
|
|
2212
2582
|
setBaseStates([]);
|
|
@@ -2237,7 +2607,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2237
2607
|
setMapOverrides(initialOverrides);
|
|
2238
2608
|
setUiOverrides([]);
|
|
2239
2609
|
}, [normalizedLayers]);
|
|
2240
|
-
(0,
|
|
2610
|
+
(0, import_react4.useEffect)(() => {
|
|
2241
2611
|
if (!layerControls) {
|
|
2242
2612
|
setControlOverrides([]);
|
|
2243
2613
|
return;
|
|
@@ -2249,7 +2619,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2249
2619
|
}));
|
|
2250
2620
|
setControlOverrides(overrides);
|
|
2251
2621
|
}, [layerControls]);
|
|
2252
|
-
(0,
|
|
2622
|
+
(0, import_react4.useEffect)(() => {
|
|
2253
2623
|
if (layerStates) {
|
|
2254
2624
|
return;
|
|
2255
2625
|
}
|
|
@@ -2259,12 +2629,12 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2259
2629
|
onLayerStateChange?.(reset);
|
|
2260
2630
|
}
|
|
2261
2631
|
}, [baseStates, effectiveStates.length, layerControls, layerStates, onLayerStateChange]);
|
|
2262
|
-
(0,
|
|
2632
|
+
(0, import_react4.useEffect)(() => {
|
|
2263
2633
|
if (layerStates) {
|
|
2264
2634
|
setEffectiveStates(layerStates);
|
|
2265
2635
|
}
|
|
2266
2636
|
}, [layerStates]);
|
|
2267
|
-
(0,
|
|
2637
|
+
(0, import_react4.useEffect)(() => {
|
|
2268
2638
|
if (layerStates) {
|
|
2269
2639
|
return;
|
|
2270
2640
|
}
|
|
@@ -2277,11 +2647,11 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2277
2647
|
setEffectiveStates(next);
|
|
2278
2648
|
onLayerStateChange?.(next);
|
|
2279
2649
|
}, [baseStates, controlOverrides, layerStates, mapOverrides, onLayerStateChange, uiOverrides]);
|
|
2280
|
-
(0,
|
|
2650
|
+
(0, import_react4.useEffect)(() => {
|
|
2281
2651
|
if (!Array.isArray(layerControls) || layerControls.length > 0) return;
|
|
2282
2652
|
setUiOverrides([]);
|
|
2283
2653
|
}, [layerControls]);
|
|
2284
|
-
(0,
|
|
2654
|
+
(0, import_react4.useEffect)(() => {
|
|
2285
2655
|
if (layerStates) {
|
|
2286
2656
|
return;
|
|
2287
2657
|
}
|
|
@@ -2301,18 +2671,13 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2301
2671
|
return [...filtered, nextEntry];
|
|
2302
2672
|
});
|
|
2303
2673
|
};
|
|
2304
|
-
const updateOpacityFromUi = (0,
|
|
2674
|
+
const updateOpacityFromUi = (0, import_react4.useCallback)(
|
|
2305
2675
|
(layerId, uiOpacity) => {
|
|
2306
2676
|
const meta = layerMetaIndex.get(String(layerId));
|
|
2307
|
-
const
|
|
2677
|
+
const baseOpacity = clampOpacity3(uiOpacity);
|
|
2678
|
+
const effectiveOpacity = calculateZoomBasedOpacity(
|
|
2308
2679
|
currentZoom,
|
|
2309
|
-
meta?.layerType,
|
|
2310
|
-
meta?.geometryType
|
|
2311
|
-
);
|
|
2312
|
-
const baseOpacity = clampOpacity3(uiOpacity / zoomFactor);
|
|
2313
|
-
const effectiveOpacity = getEffectiveLayerOpacity(
|
|
2314
2680
|
baseOpacity,
|
|
2315
|
-
currentZoom,
|
|
2316
2681
|
meta?.layerType,
|
|
2317
2682
|
meta?.geometryType
|
|
2318
2683
|
);
|
|
@@ -2345,7 +2710,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2345
2710
|
},
|
|
2346
2711
|
[currentZoom, effectiveStates, layerMetaIndex, layerStates, onLayerStateChange]
|
|
2347
2712
|
);
|
|
2348
|
-
const center = (0,
|
|
2713
|
+
const center = (0, import_react4.useMemo)(() => {
|
|
2349
2714
|
if (initialCenter) {
|
|
2350
2715
|
return initialCenter;
|
|
2351
2716
|
}
|
|
@@ -2356,36 +2721,30 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2356
2721
|
return DEFAULT_CENTER;
|
|
2357
2722
|
}, [initialCenter, map?.settings?.center]);
|
|
2358
2723
|
const zoom = initialZoom ?? map?.settings?.zoom ?? DEFAULT_ZOOM;
|
|
2359
|
-
(0,
|
|
2724
|
+
(0, import_react4.useEffect)(() => {
|
|
2360
2725
|
setCurrentZoom(zoom);
|
|
2361
2726
|
}, [zoom]);
|
|
2362
|
-
const decoratedLayers = (0,
|
|
2727
|
+
const decoratedLayers = (0, import_react4.useMemo)(() => {
|
|
2363
2728
|
return layers.map((layer) => ({
|
|
2364
2729
|
...layer,
|
|
2365
2730
|
effective: effectiveStates.find((state) => state.layerId === layer.mapLayer.layerId),
|
|
2366
2731
|
data: layerGeojson?.[layer.mapLayer.layerId] ?? layerGeojson?.[String(layer.mapLayer.layerId)] ?? null
|
|
2367
2732
|
}));
|
|
2368
2733
|
}, [effectiveStates, layerGeojson, layers]);
|
|
2369
|
-
const orderedLayers = (0,
|
|
2734
|
+
const orderedLayers = (0, import_react4.useMemo)(() => {
|
|
2370
2735
|
return [...decoratedLayers].filter((layer) => layer.effective?.visible && layer.data).sort((a, b) => a.displayOrder - b.displayOrder);
|
|
2371
2736
|
}, [decoratedLayers]);
|
|
2372
|
-
const
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
const autoZoomBBox = (0, import_react.useMemo)(() => {
|
|
2378
|
-
if (explicitZoomBBox) return null;
|
|
2379
|
-
const visibleBBoxes = orderedLayers.map((layer) => computeBBoxFromGeojson(layer.data));
|
|
2380
|
-
return mergeBBoxes(visibleBBoxes);
|
|
2381
|
-
}, [explicitZoomBBox, orderedLayers]);
|
|
2382
|
-
const resolveLayerStyle = (0, import_react.useCallback)(
|
|
2737
|
+
const autoZoomGeojson = (0, import_react4.useMemo)(
|
|
2738
|
+
() => orderedLayers.map((layer) => layer.data).filter((collection) => !!collection),
|
|
2739
|
+
[orderedLayers]
|
|
2740
|
+
);
|
|
2741
|
+
const resolveLayerStyle = (0, import_react4.useCallback)(
|
|
2383
2742
|
(layerId) => {
|
|
2384
2743
|
return getStyleByLayerId(layerId, mapLayers) ?? layerStyleIndex.get(String(layerId)) ?? null;
|
|
2385
2744
|
},
|
|
2386
2745
|
[layerStyleIndex, mapLayers]
|
|
2387
2746
|
);
|
|
2388
|
-
const labelMarkers = (0,
|
|
2747
|
+
const labelMarkers = (0, import_react4.useMemo)(() => {
|
|
2389
2748
|
const markers = [];
|
|
2390
2749
|
decoratedLayers.forEach((layerState) => {
|
|
2391
2750
|
if (!layerState.effective?.visible) return;
|
|
@@ -2395,7 +2754,14 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2395
2754
|
if (!data) return;
|
|
2396
2755
|
const resolvedStyle = resolveLayerStyle(layerState.mapLayer.layerId);
|
|
2397
2756
|
const layerColor = resolvedStyle?.fillColor ?? resolvedStyle?.color ?? "rgba(37, 99, 235, 1)";
|
|
2398
|
-
const
|
|
2757
|
+
const meta = layerMetaIndex.get(String(layerState.mapLayer.layerId));
|
|
2758
|
+
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
2759
|
+
const opacity = calculateZoomBasedOpacity(
|
|
2760
|
+
currentZoom,
|
|
2761
|
+
baseOpacity,
|
|
2762
|
+
meta?.layerType,
|
|
2763
|
+
meta?.geometryType
|
|
2764
|
+
);
|
|
2399
2765
|
data.features.forEach((feature, index) => {
|
|
2400
2766
|
const properties = feature.properties;
|
|
2401
2767
|
const value = properties?.[labelKey];
|
|
@@ -2414,26 +2780,24 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2414
2780
|
});
|
|
2415
2781
|
});
|
|
2416
2782
|
return markers;
|
|
2417
|
-
}, [decoratedLayers, labelKeyIndex, resolveLayerStyle]);
|
|
2418
|
-
const ensureLayerPanes = (0,
|
|
2783
|
+
}, [currentZoom, decoratedLayers, labelKeyIndex, layerMetaIndex, resolveLayerStyle]);
|
|
2784
|
+
const ensureLayerPanes = (0, import_react4.useCallback)(
|
|
2419
2785
|
(targetMap, targetLayers) => {
|
|
2420
2786
|
const baseZIndex = 400;
|
|
2421
2787
|
targetLayers.forEach((layer) => {
|
|
2422
2788
|
const order = Number.isFinite(layer.displayOrder) ? layer.displayOrder : 0;
|
|
2789
|
+
const orderOffset = Math.max(0, Math.min(order, 150));
|
|
2423
2790
|
const fillPaneName = `zenit-layer-${layer.layerId}-fill`;
|
|
2424
2791
|
const pointPaneName = `zenit-layer-${layer.layerId}-points`;
|
|
2425
|
-
const labelPaneName = `zenit-layer-${layer.layerId}-labels`;
|
|
2426
2792
|
const fillPane = targetMap.getPane(fillPaneName) ?? targetMap.createPane(fillPaneName);
|
|
2427
2793
|
const pointPane = targetMap.getPane(pointPaneName) ?? targetMap.createPane(pointPaneName);
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
pointPane.style.zIndex = String(baseZIndex + order + 1e3);
|
|
2431
|
-
labelPane.style.zIndex = String(baseZIndex + order + 2e3);
|
|
2794
|
+
fillPane.style.zIndex = String(baseZIndex + orderOffset);
|
|
2795
|
+
pointPane.style.zIndex = String(baseZIndex + orderOffset + 100);
|
|
2432
2796
|
});
|
|
2433
2797
|
},
|
|
2434
2798
|
[]
|
|
2435
2799
|
);
|
|
2436
|
-
const handleMapReady = (0,
|
|
2800
|
+
const handleMapReady = (0, import_react4.useCallback)(
|
|
2437
2801
|
(instance) => {
|
|
2438
2802
|
setPanesReady(false);
|
|
2439
2803
|
setMapInstance(instance);
|
|
@@ -2441,7 +2805,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2441
2805
|
},
|
|
2442
2806
|
[onMapReady]
|
|
2443
2807
|
);
|
|
2444
|
-
(0,
|
|
2808
|
+
(0, import_react4.useEffect)(() => {
|
|
2445
2809
|
if (!mapInstance) {
|
|
2446
2810
|
setPanesReady(false);
|
|
2447
2811
|
return;
|
|
@@ -2455,24 +2819,25 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2455
2819
|
}));
|
|
2456
2820
|
ensureLayerPanes(mapInstance, layerTargets);
|
|
2457
2821
|
const first = layerTargets[0];
|
|
2458
|
-
const testPane = mapInstance.getPane(`zenit-layer-${first.layerId}-
|
|
2459
|
-
|
|
2822
|
+
const testPane = mapInstance.getPane(`zenit-layer-${first.layerId}-fill`);
|
|
2823
|
+
const labelsPane = mapInstance.getPane(LABELS_PANE_NAME);
|
|
2824
|
+
if (testPane && labelsPane) {
|
|
2460
2825
|
setPanesReady(true);
|
|
2461
2826
|
}
|
|
2462
2827
|
}, [mapInstance, orderedLayers, ensureLayerPanes]);
|
|
2463
|
-
const overlayOnEachFeature = (0,
|
|
2828
|
+
const overlayOnEachFeature = (0, import_react4.useMemo)(() => {
|
|
2464
2829
|
return (feature, layer) => {
|
|
2465
2830
|
const layerId = getFeatureLayerId(feature) ?? void 0;
|
|
2466
2831
|
const geometryType = feature?.geometry?.type;
|
|
2467
|
-
const isPointFeature = geometryType === "Point" || geometryType === "MultiPoint" || layer instanceof
|
|
2468
|
-
const originalStyle = layer instanceof
|
|
2832
|
+
const isPointFeature = geometryType === "Point" || geometryType === "MultiPoint" || layer instanceof import_leaflet4.default.CircleMarker;
|
|
2833
|
+
const originalStyle = layer instanceof import_leaflet4.default.Path ? {
|
|
2469
2834
|
color: layer.options.color,
|
|
2470
2835
|
weight: layer.options.weight,
|
|
2471
2836
|
fillColor: layer.options.fillColor,
|
|
2472
2837
|
opacity: layer.options.opacity,
|
|
2473
2838
|
fillOpacity: layer.options.fillOpacity
|
|
2474
2839
|
} : null;
|
|
2475
|
-
const originalRadius = layer instanceof
|
|
2840
|
+
const originalRadius = layer instanceof import_leaflet4.default.CircleMarker ? layer.getRadius() : null;
|
|
2476
2841
|
if (featureInfoMode === "popup") {
|
|
2477
2842
|
const content = buildFeaturePopupHtml(feature);
|
|
2478
2843
|
if (content) {
|
|
@@ -2481,11 +2846,10 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2481
2846
|
maxWidth,
|
|
2482
2847
|
minWidth,
|
|
2483
2848
|
maxHeight,
|
|
2484
|
-
className: "
|
|
2849
|
+
className: "custom-leaflet-popup",
|
|
2485
2850
|
autoPan: true,
|
|
2486
2851
|
closeButton: true,
|
|
2487
|
-
keepInView: true
|
|
2488
|
-
offset: import_leaflet.default.point(0, -24)
|
|
2852
|
+
keepInView: true
|
|
2489
2853
|
});
|
|
2490
2854
|
}
|
|
2491
2855
|
}
|
|
@@ -2506,7 +2870,8 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2506
2870
|
id: layerId,
|
|
2507
2871
|
geometry: feature.geometry
|
|
2508
2872
|
}).then((response) => {
|
|
2509
|
-
const
|
|
2873
|
+
const geo = extractGeoJsonFeatureCollection(response);
|
|
2874
|
+
const candidates = geo?.features ?? [];
|
|
2510
2875
|
const resolved = pickIntersectFeature(feature, candidates);
|
|
2511
2876
|
if (!resolved?.properties) return;
|
|
2512
2877
|
const mergedProperties = {
|
|
@@ -2529,7 +2894,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2529
2894
|
onFeatureClick?.(feature, layerId);
|
|
2530
2895
|
});
|
|
2531
2896
|
layer.on("mouseover", () => {
|
|
2532
|
-
if (layer instanceof
|
|
2897
|
+
if (layer instanceof import_leaflet4.default.Path && originalStyle) {
|
|
2533
2898
|
layer.setStyle({
|
|
2534
2899
|
...originalStyle,
|
|
2535
2900
|
weight: (originalStyle.weight ?? 2) + 1,
|
|
@@ -2537,16 +2902,16 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2537
2902
|
fillOpacity: Math.min(1, (originalStyle.fillOpacity ?? 0.8) + 0.1)
|
|
2538
2903
|
});
|
|
2539
2904
|
}
|
|
2540
|
-
if (layer instanceof
|
|
2905
|
+
if (layer instanceof import_leaflet4.default.CircleMarker && typeof originalRadius === "number") {
|
|
2541
2906
|
layer.setRadius(originalRadius + 1);
|
|
2542
2907
|
}
|
|
2543
2908
|
onFeatureHover?.(feature, layerId);
|
|
2544
2909
|
});
|
|
2545
2910
|
layer.on("mouseout", () => {
|
|
2546
|
-
if (layer instanceof
|
|
2911
|
+
if (layer instanceof import_leaflet4.default.Path && originalStyle) {
|
|
2547
2912
|
layer.setStyle(originalStyle);
|
|
2548
2913
|
}
|
|
2549
|
-
if (layer instanceof
|
|
2914
|
+
if (layer instanceof import_leaflet4.default.CircleMarker && typeof originalRadius === "number") {
|
|
2550
2915
|
layer.setRadius(originalRadius);
|
|
2551
2916
|
}
|
|
2552
2917
|
});
|
|
@@ -2558,80 +2923,20 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2558
2923
|
const resolvedStyle = featureStyleOverrides ? { ...style ?? {}, ...featureStyleOverrides } : style;
|
|
2559
2924
|
const geometryType = feature?.geometry?.type;
|
|
2560
2925
|
const resolvedLayerType = layerType ?? geometryType;
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
resolvedLayerType
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
color: resolvedStyle?.color ?? resolvedStyle?.fillColor ?? "#2563eb",
|
|
2573
|
-
weight: resolvedStyle?.weight ?? 2,
|
|
2574
|
-
fillColor: resolvedStyle?.fillColor ?? resolvedStyle?.color ?? "#2563eb",
|
|
2575
|
-
opacity: strokeOpacity,
|
|
2576
|
-
fillOpacity
|
|
2926
|
+
return layerStyleToLeaflet({
|
|
2927
|
+
baseOpacity,
|
|
2928
|
+
zoom: currentZoom,
|
|
2929
|
+
layerStyle: resolvedStyle,
|
|
2930
|
+
geometryType,
|
|
2931
|
+
layerType: resolvedLayerType
|
|
2932
|
+
});
|
|
2933
|
+
};
|
|
2934
|
+
const makeStyleFnForLayer = (layerId) => {
|
|
2935
|
+
return (feature, layerType, baseOpacity) => {
|
|
2936
|
+
return buildLayerStyle(layerId, baseOpacity ?? 1, feature, layerType);
|
|
2577
2937
|
};
|
|
2578
2938
|
};
|
|
2579
|
-
|
|
2580
|
-
const size = 60;
|
|
2581
|
-
const innerSize = 44;
|
|
2582
|
-
const textStyles = getLabelTextStyles(color);
|
|
2583
|
-
const safeLabel = escapeHtml(label);
|
|
2584
|
-
const clampedOpacity = Math.min(1, Math.max(0.92, opacity));
|
|
2585
|
-
const innerBackground = withAlpha(color, 0.9);
|
|
2586
|
-
return import_leaflet.default.divIcon({
|
|
2587
|
-
className: "zenit-label-marker",
|
|
2588
|
-
iconSize: [size, size],
|
|
2589
|
-
iconAnchor: [size / 2, size / 2],
|
|
2590
|
-
html: `
|
|
2591
|
-
<div
|
|
2592
|
-
title="${safeLabel}"
|
|
2593
|
-
style="
|
|
2594
|
-
width:${size}px;
|
|
2595
|
-
height:${size}px;
|
|
2596
|
-
border-radius:9999px;
|
|
2597
|
-
background:rgba(255, 255, 255, 0.95);
|
|
2598
|
-
border:3px solid rgba(255, 255, 255, 1);
|
|
2599
|
-
display:flex;
|
|
2600
|
-
align-items:center;
|
|
2601
|
-
justify-content:center;
|
|
2602
|
-
opacity:${clampedOpacity};
|
|
2603
|
-
box-shadow:0 2px 6px rgba(0, 0, 0, 0.25);
|
|
2604
|
-
pointer-events:none;
|
|
2605
|
-
"
|
|
2606
|
-
>
|
|
2607
|
-
<div
|
|
2608
|
-
style="
|
|
2609
|
-
width:${innerSize}px;
|
|
2610
|
-
height:${innerSize}px;
|
|
2611
|
-
border-radius:9999px;
|
|
2612
|
-
background:${innerBackground};
|
|
2613
|
-
display:flex;
|
|
2614
|
-
align-items:center;
|
|
2615
|
-
justify-content:center;
|
|
2616
|
-
box-shadow:inset 0 0 0 1px rgba(15, 23, 42, 0.12);
|
|
2617
|
-
"
|
|
2618
|
-
>
|
|
2619
|
-
<span
|
|
2620
|
-
style="
|
|
2621
|
-
color:${textStyles.color};
|
|
2622
|
-
font-size:20px;
|
|
2623
|
-
font-weight:800;
|
|
2624
|
-
text-shadow:${textStyles.shadow};
|
|
2625
|
-
"
|
|
2626
|
-
>
|
|
2627
|
-
${safeLabel}
|
|
2628
|
-
</span>
|
|
2629
|
-
</div>
|
|
2630
|
-
</div>
|
|
2631
|
-
`
|
|
2632
|
-
});
|
|
2633
|
-
}, []);
|
|
2634
|
-
(0, import_react.useImperativeHandle)(ref, () => ({
|
|
2939
|
+
(0, import_react4.useImperativeHandle)(ref, () => ({
|
|
2635
2940
|
setLayerOpacity: (layerId, opacity) => {
|
|
2636
2941
|
upsertUiOverride(layerId, { overrideOpacity: opacity });
|
|
2637
2942
|
},
|
|
@@ -2681,10 +2986,10 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2681
2986
|
getMapInstance: () => mapInstance
|
|
2682
2987
|
}), [effectiveStates, mapInstance]);
|
|
2683
2988
|
if (loadingMap) {
|
|
2684
|
-
return /* @__PURE__ */ (0,
|
|
2989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { padding: 16, height, width }, children: "Cargando mapa..." });
|
|
2685
2990
|
}
|
|
2686
2991
|
if (mapError) {
|
|
2687
|
-
return /* @__PURE__ */ (0,
|
|
2992
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { padding: 16, height, width, color: "red" }, children: [
|
|
2688
2993
|
"Error al cargar mapa: ",
|
|
2689
2994
|
mapError
|
|
2690
2995
|
] });
|
|
@@ -2696,7 +3001,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2696
3001
|
setCurrentZoom(zoomValue);
|
|
2697
3002
|
onZoomChange?.(zoomValue);
|
|
2698
3003
|
};
|
|
2699
|
-
return /* @__PURE__ */ (0,
|
|
3004
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2700
3005
|
"div",
|
|
2701
3006
|
{
|
|
2702
3007
|
style: {
|
|
@@ -2709,88 +3014,111 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2709
3014
|
boxSizing: "border-box"
|
|
2710
3015
|
},
|
|
2711
3016
|
children: [
|
|
2712
|
-
/* @__PURE__ */ (0,
|
|
2713
|
-
|
|
3017
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3018
|
+
"div",
|
|
2714
3019
|
{
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_leaflet.ZoomControl, { position: "topright" }),
|
|
2729
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MapInstanceBridge, { onReady: handleMapReady }),
|
|
2730
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FitToBounds, { bbox: explicitZoomBBox ?? void 0 }),
|
|
2731
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AutoFitToBounds, { bbox: autoZoomBBox ?? void 0, enabled: !explicitZoomBBox }),
|
|
2732
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ZoomBasedOpacityHandler, { onZoomChange: handleZoomChange }),
|
|
2733
|
-
orderedLayers.map((layerState) => {
|
|
2734
|
-
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
2735
|
-
const fillPaneName = `zenit-layer-${layerState.mapLayer.layerId}-fill`;
|
|
2736
|
-
const pointsPaneName = `zenit-layer-${layerState.mapLayer.layerId}-points`;
|
|
2737
|
-
const labelPaneName = `zenit-layer-${layerState.mapLayer.layerId}-labels`;
|
|
2738
|
-
const layerType = layerState.layer?.layerType ?? layerState.mapLayer.layerType ?? void 0;
|
|
2739
|
-
const data = layerState.data?.features ?? [];
|
|
2740
|
-
const fillFeatures = data.filter(isNonPointGeometry);
|
|
2741
|
-
const pointFeatures = data.filter(isPointGeometry);
|
|
2742
|
-
const fillData = fillFeatures.length > 0 ? buildFeatureCollection(fillFeatures) : null;
|
|
2743
|
-
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
2744
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.default.Fragment, { children: [
|
|
2745
|
-
fillData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2746
|
-
import_react_leaflet.GeoJSON,
|
|
3020
|
+
className: `zenit-map-shell${isPopupOpen ? " popup-open" : ""}`,
|
|
3021
|
+
style: { flex: 1, position: "relative" },
|
|
3022
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3023
|
+
import_react_leaflet4.MapContainer,
|
|
3024
|
+
{
|
|
3025
|
+
center,
|
|
3026
|
+
zoom,
|
|
3027
|
+
style: { height: "100%", width: "100%" },
|
|
3028
|
+
scrollWheelZoom: true,
|
|
3029
|
+
zoomControl: false,
|
|
3030
|
+
children: [
|
|
3031
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3032
|
+
import_react_leaflet4.TileLayer,
|
|
2747
3033
|
{
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
style: (feature) => buildLayerStyle(layerState.mapLayer.layerId, baseOpacity, feature, layerType),
|
|
2751
|
-
onEachFeature: overlayOnEachFeature
|
|
3034
|
+
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
3035
|
+
attribution: "\xA9 OpenStreetMap contributors"
|
|
2752
3036
|
}
|
|
2753
3037
|
),
|
|
2754
|
-
|
|
2755
|
-
|
|
3038
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_leaflet4.ZoomControl, { position: "topright" }),
|
|
3039
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MapInstanceBridge, { onReady: handleMapReady }),
|
|
3040
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3041
|
+
BBoxZoomHandler,
|
|
2756
3042
|
{
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
radius: isMobile ? 8 : 6,
|
|
2761
|
-
...buildLayerStyle(layerState.mapLayer.layerId, baseOpacity, feature, layerType)
|
|
2762
|
-
}),
|
|
2763
|
-
onEachFeature: overlayOnEachFeature
|
|
3043
|
+
bbox: zoomToBbox ?? void 0,
|
|
3044
|
+
geojson: zoomToGeojson ?? void 0,
|
|
3045
|
+
autoGeojson: autoZoomGeojson
|
|
2764
3046
|
}
|
|
2765
3047
|
),
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
3048
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ZoomBasedOpacityHandler, { onZoomChange: handleZoomChange }),
|
|
3049
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LocationControl, {}),
|
|
3050
|
+
orderedLayers.map((layerState) => {
|
|
3051
|
+
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
3052
|
+
const fillPaneName = `zenit-layer-${layerState.mapLayer.layerId}-fill`;
|
|
3053
|
+
const pointsPaneName = `zenit-layer-${layerState.mapLayer.layerId}-points`;
|
|
3054
|
+
const layerType = layerState.layer?.layerType ?? layerState.mapLayer.layerType ?? void 0;
|
|
3055
|
+
const labelKey = labelKeyIndex.get(String(layerState.mapLayer.layerId));
|
|
3056
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.default.Fragment, { children: [
|
|
3057
|
+
layerState.data && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3058
|
+
LayerGeoJson,
|
|
3059
|
+
{
|
|
3060
|
+
layerId: layerState.mapLayer.layerId,
|
|
3061
|
+
data: layerState.data,
|
|
3062
|
+
baseOpacity,
|
|
3063
|
+
isMobile,
|
|
3064
|
+
panesReady,
|
|
3065
|
+
mapInstance,
|
|
3066
|
+
fillPaneName,
|
|
3067
|
+
pointsPaneName,
|
|
3068
|
+
layerType,
|
|
3069
|
+
styleFn: makeStyleFnForLayer(layerState.mapLayer.layerId),
|
|
3070
|
+
onEachFeature: overlayOnEachFeature,
|
|
3071
|
+
onPolygonLabel: labelKey ? (feature, layer) => {
|
|
3072
|
+
const geometryType = feature?.geometry?.type;
|
|
3073
|
+
if (geometryType !== "Polygon" && geometryType !== "MultiPolygon") return;
|
|
3074
|
+
const properties = feature?.properties;
|
|
3075
|
+
const value = properties?.[labelKey];
|
|
3076
|
+
if (!value || !layer.bindTooltip) return;
|
|
3077
|
+
layer.bindTooltip(String(value), {
|
|
3078
|
+
sticky: true,
|
|
3079
|
+
direction: "center",
|
|
3080
|
+
opacity: 0.9,
|
|
3081
|
+
className: "polygon-label-tooltip"
|
|
3082
|
+
});
|
|
3083
|
+
} : void 0
|
|
3084
|
+
}
|
|
3085
|
+
),
|
|
3086
|
+
panesReady && mapInstance?.getPane(LABELS_PANE_NAME) ? labelMarkers.filter(
|
|
3087
|
+
(marker) => String(marker.layerId) === String(layerState.mapLayer.layerId)
|
|
3088
|
+
).map((marker) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3089
|
+
import_react_leaflet4.Marker,
|
|
3090
|
+
{
|
|
3091
|
+
position: marker.position,
|
|
3092
|
+
icon: createCustomIcon(marker.label, marker.opacity, marker.color),
|
|
3093
|
+
interactive: false,
|
|
3094
|
+
pane: LABELS_PANE_NAME
|
|
3095
|
+
},
|
|
3096
|
+
marker.key
|
|
3097
|
+
)) : null
|
|
3098
|
+
] }, layerState.mapLayer.layerId.toString());
|
|
3099
|
+
}),
|
|
3100
|
+
overlayGeojson && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3101
|
+
LayerGeoJson,
|
|
2770
3102
|
{
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
},
|
|
2791
|
-
String(mapId)
|
|
2792
|
-
) }),
|
|
2793
|
-
showLayerPanel && decoratedLayers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
3103
|
+
layerId: "overlay-geojson",
|
|
3104
|
+
data: overlayGeojson,
|
|
3105
|
+
baseOpacity: 1,
|
|
3106
|
+
isMobile,
|
|
3107
|
+
panesReady,
|
|
3108
|
+
mapInstance,
|
|
3109
|
+
fillPaneName: "zenit-overlay-fill",
|
|
3110
|
+
pointsPaneName: "zenit-overlay-points",
|
|
3111
|
+
styleFn: overlayStyleFn,
|
|
3112
|
+
onEachFeature: overlayOnEachFeature
|
|
3113
|
+
}
|
|
3114
|
+
)
|
|
3115
|
+
]
|
|
3116
|
+
},
|
|
3117
|
+
String(mapId)
|
|
3118
|
+
)
|
|
3119
|
+
}
|
|
3120
|
+
),
|
|
3121
|
+
showLayerPanel && decoratedLayers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2794
3122
|
"div",
|
|
2795
3123
|
{
|
|
2796
3124
|
style: {
|
|
@@ -2803,7 +3131,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2803
3131
|
overflowY: "auto"
|
|
2804
3132
|
},
|
|
2805
3133
|
children: [
|
|
2806
|
-
overlayGeojson && /* @__PURE__ */ (0,
|
|
3134
|
+
overlayGeojson && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2807
3135
|
"div",
|
|
2808
3136
|
{
|
|
2809
3137
|
style: {
|
|
@@ -2815,8 +3143,8 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2815
3143
|
marginBottom: 12
|
|
2816
3144
|
},
|
|
2817
3145
|
children: [
|
|
2818
|
-
/* @__PURE__ */ (0,
|
|
2819
|
-
/* @__PURE__ */ (0,
|
|
3146
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontWeight: 600, marginBottom: 4 }, children: "Overlay activo" }),
|
|
3147
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { fontSize: 13 }, children: [
|
|
2820
3148
|
"GeoJSON externo con ",
|
|
2821
3149
|
(overlayGeojson.features?.length ?? 0).toLocaleString(),
|
|
2822
3150
|
" elementos."
|
|
@@ -2824,14 +3152,14 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2824
3152
|
]
|
|
2825
3153
|
}
|
|
2826
3154
|
),
|
|
2827
|
-
/* @__PURE__ */ (0,
|
|
2828
|
-
decoratedLayers.map((layerState) => /* @__PURE__ */ (0,
|
|
3155
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontWeight: 600, marginBottom: 12 }, children: "Capas" }),
|
|
3156
|
+
decoratedLayers.map((layerState) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2829
3157
|
"div",
|
|
2830
3158
|
{
|
|
2831
3159
|
style: { borderBottom: "1px solid #e5e7eb", paddingBottom: 10, marginBottom: 10 },
|
|
2832
3160
|
children: [
|
|
2833
|
-
/* @__PURE__ */ (0,
|
|
2834
|
-
/* @__PURE__ */ (0,
|
|
3161
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
|
3162
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2835
3163
|
"input",
|
|
2836
3164
|
{
|
|
2837
3165
|
type: "checkbox",
|
|
@@ -2842,17 +3170,17 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2842
3170
|
}
|
|
2843
3171
|
}
|
|
2844
3172
|
),
|
|
2845
|
-
/* @__PURE__ */ (0,
|
|
3173
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: layerState.layer?.name ?? `Capa ${layerState.mapLayer.layerId}` })
|
|
2846
3174
|
] }),
|
|
2847
|
-
/* @__PURE__ */ (0,
|
|
2848
|
-
/* @__PURE__ */ (0,
|
|
2849
|
-
/* @__PURE__ */ (0,
|
|
2850
|
-
/* @__PURE__ */ (0,
|
|
3175
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { marginTop: 8 }, children: [
|
|
3176
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 4 }, children: [
|
|
3177
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "#4a5568" }, children: "Opacidad" }),
|
|
3178
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
|
|
2851
3179
|
Math.round((layerState.effective?.opacity ?? 1) * 100),
|
|
2852
3180
|
"%"
|
|
2853
3181
|
] })
|
|
2854
3182
|
] }),
|
|
2855
|
-
/* @__PURE__ */ (0,
|
|
3183
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2856
3184
|
"input",
|
|
2857
3185
|
{
|
|
2858
3186
|
type: "range",
|
|
@@ -2882,13 +3210,13 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2882
3210
|
ZenitMap.displayName = "ZenitMap";
|
|
2883
3211
|
|
|
2884
3212
|
// src/react/ZenitLayerManager.tsx
|
|
2885
|
-
var
|
|
3213
|
+
var import_react5 = __toESM(require("react"));
|
|
2886
3214
|
|
|
2887
3215
|
// src/react/icons.tsx
|
|
2888
3216
|
var import_lucide_react = require("lucide-react");
|
|
2889
3217
|
|
|
2890
3218
|
// src/react/ZenitLayerManager.tsx
|
|
2891
|
-
var
|
|
3219
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
2892
3220
|
var FLOAT_TOLERANCE = 1e-3;
|
|
2893
3221
|
function areEffectiveStatesEqual(a, b) {
|
|
2894
3222
|
if (a.length !== b.length) return false;
|
|
@@ -2928,15 +3256,15 @@ var ZenitLayerManager = ({
|
|
|
2928
3256
|
layerFeatureCounts,
|
|
2929
3257
|
mapLayers
|
|
2930
3258
|
}) => {
|
|
2931
|
-
const [map, setMap] = (0,
|
|
2932
|
-
const [loadingMap, setLoadingMap] = (0,
|
|
2933
|
-
const [mapError, setMapError] = (0,
|
|
2934
|
-
const [layers, setLayers] = (0,
|
|
2935
|
-
const [activeTab, setActiveTab] = (0,
|
|
2936
|
-
const [panelVisible, setPanelVisible] = (0,
|
|
2937
|
-
const lastEmittedStatesRef = (0,
|
|
3259
|
+
const [map, setMap] = (0, import_react5.useState)(null);
|
|
3260
|
+
const [loadingMap, setLoadingMap] = (0, import_react5.useState)(false);
|
|
3261
|
+
const [mapError, setMapError] = (0, import_react5.useState)(null);
|
|
3262
|
+
const [layers, setLayers] = (0, import_react5.useState)([]);
|
|
3263
|
+
const [activeTab, setActiveTab] = (0, import_react5.useState)("layers");
|
|
3264
|
+
const [panelVisible, setPanelVisible] = (0, import_react5.useState)(true);
|
|
3265
|
+
const lastEmittedStatesRef = (0, import_react5.useRef)(null);
|
|
2938
3266
|
const isControlled = Array.isArray(layerStates) && typeof onLayerStatesChange === "function";
|
|
2939
|
-
const baseStates = (0,
|
|
3267
|
+
const baseStates = (0, import_react5.useMemo)(
|
|
2940
3268
|
() => initLayerStates(
|
|
2941
3269
|
layers.map((entry) => ({
|
|
2942
3270
|
...entry.mapLayer,
|
|
@@ -2947,7 +3275,7 @@ var ZenitLayerManager = ({
|
|
|
2947
3275
|
),
|
|
2948
3276
|
[layers]
|
|
2949
3277
|
);
|
|
2950
|
-
const overrideStates = (0,
|
|
3278
|
+
const overrideStates = (0, import_react5.useMemo)(
|
|
2951
3279
|
() => layers.map(
|
|
2952
3280
|
(entry) => ({
|
|
2953
3281
|
layerId: entry.mapLayer.layerId,
|
|
@@ -2957,11 +3285,11 @@ var ZenitLayerManager = ({
|
|
|
2957
3285
|
),
|
|
2958
3286
|
[layers]
|
|
2959
3287
|
);
|
|
2960
|
-
const effectiveStates = (0,
|
|
3288
|
+
const effectiveStates = (0, import_react5.useMemo)(
|
|
2961
3289
|
() => layerStates ?? applyLayerOverrides(baseStates, overrideStates),
|
|
2962
3290
|
[baseStates, layerStates, overrideStates]
|
|
2963
3291
|
);
|
|
2964
|
-
const layerMetaIndex = (0,
|
|
3292
|
+
const layerMetaIndex = (0, import_react5.useMemo)(() => {
|
|
2965
3293
|
const index = /* @__PURE__ */ new Map();
|
|
2966
3294
|
mapLayers?.forEach((entry) => {
|
|
2967
3295
|
const key = String(entry.layerId);
|
|
@@ -2975,7 +3303,7 @@ var ZenitLayerManager = ({
|
|
|
2975
3303
|
});
|
|
2976
3304
|
return index;
|
|
2977
3305
|
}, [map, mapLayers]);
|
|
2978
|
-
const resolveUserOpacity =
|
|
3306
|
+
const resolveUserOpacity = import_react5.default.useCallback((state) => {
|
|
2979
3307
|
if (typeof state.overrideOpacity === "number") return state.overrideOpacity;
|
|
2980
3308
|
if (typeof state.overrideOpacity === "string") {
|
|
2981
3309
|
const parsed = Number.parseFloat(state.overrideOpacity);
|
|
@@ -2983,7 +3311,7 @@ var ZenitLayerManager = ({
|
|
|
2983
3311
|
}
|
|
2984
3312
|
return state.opacity ?? 1;
|
|
2985
3313
|
}, []);
|
|
2986
|
-
const resolveEffectiveOpacity =
|
|
3314
|
+
const resolveEffectiveOpacity = import_react5.default.useCallback(
|
|
2987
3315
|
(layerId, userOpacity) => {
|
|
2988
3316
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
2989
3317
|
return userOpacity;
|
|
@@ -2999,7 +3327,7 @@ var ZenitLayerManager = ({
|
|
|
2999
3327
|
},
|
|
3000
3328
|
[autoOpacityConfig, autoOpacityOnZoom, layerMetaIndex, mapZoom]
|
|
3001
3329
|
);
|
|
3002
|
-
const effectiveStatesWithZoom = (0,
|
|
3330
|
+
const effectiveStatesWithZoom = (0, import_react5.useMemo)(() => {
|
|
3003
3331
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
3004
3332
|
return effectiveStates;
|
|
3005
3333
|
}
|
|
@@ -3013,7 +3341,7 @@ var ZenitLayerManager = ({
|
|
|
3013
3341
|
};
|
|
3014
3342
|
});
|
|
3015
3343
|
}, [autoOpacityOnZoom, effectiveStates, mapZoom, resolveEffectiveOpacity, resolveUserOpacity]);
|
|
3016
|
-
(0,
|
|
3344
|
+
(0, import_react5.useEffect)(() => {
|
|
3017
3345
|
let cancelled = false;
|
|
3018
3346
|
setLoadingMap(true);
|
|
3019
3347
|
setMapError(null);
|
|
@@ -3045,12 +3373,12 @@ var ZenitLayerManager = ({
|
|
|
3045
3373
|
cancelled = true;
|
|
3046
3374
|
};
|
|
3047
3375
|
}, [client.maps, mapId]);
|
|
3048
|
-
(0,
|
|
3376
|
+
(0, import_react5.useEffect)(() => {
|
|
3049
3377
|
if (!showUploadTab && activeTab === "upload") {
|
|
3050
3378
|
setActiveTab("layers");
|
|
3051
3379
|
}
|
|
3052
3380
|
}, [activeTab, showUploadTab]);
|
|
3053
|
-
(0,
|
|
3381
|
+
(0, import_react5.useEffect)(() => {
|
|
3054
3382
|
if (isControlled) return;
|
|
3055
3383
|
if (!onLayerStatesChange) return;
|
|
3056
3384
|
const emitStates = autoOpacityOnZoom && typeof mapZoom === "number" ? effectiveStatesWithZoom : effectiveStates;
|
|
@@ -3068,7 +3396,7 @@ var ZenitLayerManager = ({
|
|
|
3068
3396
|
mapZoom,
|
|
3069
3397
|
onLayerStatesChange
|
|
3070
3398
|
]);
|
|
3071
|
-
const updateLayerVisible =
|
|
3399
|
+
const updateLayerVisible = import_react5.default.useCallback(
|
|
3072
3400
|
(layerId, visible) => {
|
|
3073
3401
|
if (!onLayerStatesChange) return;
|
|
3074
3402
|
const next = effectiveStates.map(
|
|
@@ -3078,7 +3406,7 @@ var ZenitLayerManager = ({
|
|
|
3078
3406
|
},
|
|
3079
3407
|
[effectiveStates, onLayerStatesChange]
|
|
3080
3408
|
);
|
|
3081
|
-
const updateLayerOpacity =
|
|
3409
|
+
const updateLayerOpacity = import_react5.default.useCallback(
|
|
3082
3410
|
(layerId, opacity) => {
|
|
3083
3411
|
if (!onLayerStatesChange) return;
|
|
3084
3412
|
const adjustedOpacity = resolveEffectiveOpacity(layerId, opacity);
|
|
@@ -3089,7 +3417,7 @@ var ZenitLayerManager = ({
|
|
|
3089
3417
|
},
|
|
3090
3418
|
[effectiveStates, onLayerStatesChange, resolveEffectiveOpacity]
|
|
3091
3419
|
);
|
|
3092
|
-
const resolveFeatureCount =
|
|
3420
|
+
const resolveFeatureCount = import_react5.default.useCallback(
|
|
3093
3421
|
(layerId, layer) => {
|
|
3094
3422
|
const resolvedFeatureCount = layerFeatureCounts?.[layerId] ?? layerFeatureCounts?.[String(layerId)];
|
|
3095
3423
|
if (typeof resolvedFeatureCount === "number") return resolvedFeatureCount;
|
|
@@ -3098,7 +3426,7 @@ var ZenitLayerManager = ({
|
|
|
3098
3426
|
},
|
|
3099
3427
|
[layerFeatureCounts]
|
|
3100
3428
|
);
|
|
3101
|
-
const decoratedLayers = (0,
|
|
3429
|
+
const decoratedLayers = (0, import_react5.useMemo)(() => {
|
|
3102
3430
|
return layers.map((entry) => ({
|
|
3103
3431
|
...entry,
|
|
3104
3432
|
effective: effectiveStates.find((state) => state.layerId === entry.mapLayer.layerId),
|
|
@@ -3127,7 +3455,7 @@ var ZenitLayerManager = ({
|
|
|
3127
3455
|
return String(a.mapLayer.layerId).localeCompare(String(b.mapLayer.layerId));
|
|
3128
3456
|
});
|
|
3129
3457
|
}, [effectiveStates, layers, resolveFeatureCount]);
|
|
3130
|
-
const resolveLayerStyle =
|
|
3458
|
+
const resolveLayerStyle = import_react5.default.useCallback(
|
|
3131
3459
|
(layerId) => {
|
|
3132
3460
|
const layerKey = String(layerId);
|
|
3133
3461
|
const fromProp = mapLayers?.find((entry) => String(entry.layerId) === layerKey)?.style;
|
|
@@ -3157,10 +3485,10 @@ var ZenitLayerManager = ({
|
|
|
3157
3485
|
...height ? { height } : {}
|
|
3158
3486
|
};
|
|
3159
3487
|
if (loadingMap) {
|
|
3160
|
-
return /* @__PURE__ */ (0,
|
|
3488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: panelStyle, children: "Cargando capas\u2026" });
|
|
3161
3489
|
}
|
|
3162
3490
|
if (mapError) {
|
|
3163
|
-
return /* @__PURE__ */ (0,
|
|
3491
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className, style: { ...panelStyle, color: "#c53030" }, children: [
|
|
3164
3492
|
"Error al cargar mapa: ",
|
|
3165
3493
|
mapError
|
|
3166
3494
|
] });
|
|
@@ -3178,7 +3506,7 @@ var ZenitLayerManager = ({
|
|
|
3178
3506
|
boxShadow: "0 1px 0 rgba(148, 163, 184, 0.25)"
|
|
3179
3507
|
};
|
|
3180
3508
|
const renderLayerCards = () => {
|
|
3181
|
-
return /* @__PURE__ */ (0,
|
|
3509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: decoratedLayers.map((layerState) => {
|
|
3182
3510
|
const layerId = layerState.mapLayer.layerId;
|
|
3183
3511
|
const layerName = layerState.layerName ?? `Capa ${layerId}`;
|
|
3184
3512
|
const visible = layerState.effective?.visible ?? false;
|
|
@@ -3188,7 +3516,7 @@ var ZenitLayerManager = ({
|
|
|
3188
3516
|
const muted = !visible;
|
|
3189
3517
|
const opacityPercent = Math.round(userOpacity * 100);
|
|
3190
3518
|
const sliderBackground = `linear-gradient(to right, ${layerColor} 0%, ${layerColor} ${opacityPercent}%, #e5e7eb ${opacityPercent}%, #e5e7eb 100%)`;
|
|
3191
|
-
return /* @__PURE__ */ (0,
|
|
3519
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3192
3520
|
"div",
|
|
3193
3521
|
{
|
|
3194
3522
|
className: `zlm-card${muted ? " is-muted" : ""}`,
|
|
@@ -3203,9 +3531,9 @@ var ZenitLayerManager = ({
|
|
|
3203
3531
|
width: "100%"
|
|
3204
3532
|
},
|
|
3205
3533
|
children: [
|
|
3206
|
-
/* @__PURE__ */ (0,
|
|
3207
|
-
/* @__PURE__ */ (0,
|
|
3208
|
-
/* @__PURE__ */ (0,
|
|
3534
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
|
|
3535
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: 10, alignItems: "flex-start", minWidth: 0, flex: 1 }, children: [
|
|
3536
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3209
3537
|
"div",
|
|
3210
3538
|
{
|
|
3211
3539
|
style: {
|
|
@@ -3220,7 +3548,7 @@ var ZenitLayerManager = ({
|
|
|
3220
3548
|
title: "Color de la capa"
|
|
3221
3549
|
}
|
|
3222
3550
|
),
|
|
3223
|
-
showLayerVisibilityIcon && /* @__PURE__ */ (0,
|
|
3551
|
+
showLayerVisibilityIcon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3224
3552
|
"button",
|
|
3225
3553
|
{
|
|
3226
3554
|
type: "button",
|
|
@@ -3231,11 +3559,11 @@ var ZenitLayerManager = ({
|
|
|
3231
3559
|
)
|
|
3232
3560
|
),
|
|
3233
3561
|
"aria-label": visible ? "Ocultar capa" : "Mostrar capa",
|
|
3234
|
-
children: visible ? /* @__PURE__ */ (0,
|
|
3562
|
+
children: visible ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Eye, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.EyeOff, { size: 16 })
|
|
3235
3563
|
}
|
|
3236
3564
|
),
|
|
3237
|
-
/* @__PURE__ */ (0,
|
|
3238
|
-
/* @__PURE__ */ (0,
|
|
3565
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { minWidth: 0, flex: 1 }, children: [
|
|
3566
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3239
3567
|
"div",
|
|
3240
3568
|
{
|
|
3241
3569
|
className: "zlm-layer-name",
|
|
@@ -3253,26 +3581,26 @@ var ZenitLayerManager = ({
|
|
|
3253
3581
|
children: layerName
|
|
3254
3582
|
}
|
|
3255
3583
|
),
|
|
3256
|
-
/* @__PURE__ */ (0,
|
|
3584
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: muted ? "#94a3b8" : "#64748b", fontSize: 12 }, children: [
|
|
3257
3585
|
"ID ",
|
|
3258
3586
|
layerId
|
|
3259
3587
|
] })
|
|
3260
3588
|
] })
|
|
3261
3589
|
] }),
|
|
3262
|
-
/* @__PURE__ */ (0,
|
|
3590
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", alignItems: "flex-start", gap: 6, flexShrink: 0 }, children: typeof featureCount === "number" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "zlm-badge", children: [
|
|
3263
3591
|
featureCount.toLocaleString(),
|
|
3264
3592
|
" features"
|
|
3265
3593
|
] }) })
|
|
3266
3594
|
] }),
|
|
3267
|
-
/* @__PURE__ */ (0,
|
|
3268
|
-
/* @__PURE__ */ (0,
|
|
3269
|
-
/* @__PURE__ */ (0,
|
|
3270
|
-
/* @__PURE__ */ (0,
|
|
3595
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", gap: 10, alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { flex: 1 }, children: [
|
|
3596
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 6, color: "#64748b", fontSize: 12 }, children: [
|
|
3597
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Opacidad" }),
|
|
3598
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
|
|
3271
3599
|
opacityPercent,
|
|
3272
3600
|
"%"
|
|
3273
3601
|
] })
|
|
3274
3602
|
] }),
|
|
3275
|
-
/* @__PURE__ */ (0,
|
|
3603
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3276
3604
|
"input",
|
|
3277
3605
|
{
|
|
3278
3606
|
className: "zlm-range",
|
|
@@ -3310,8 +3638,8 @@ var ZenitLayerManager = ({
|
|
|
3310
3638
|
);
|
|
3311
3639
|
}) });
|
|
3312
3640
|
};
|
|
3313
|
-
return /* @__PURE__ */ (0,
|
|
3314
|
-
/* @__PURE__ */ (0,
|
|
3641
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: ["zenit-layer-manager", className].filter(Boolean).join(" "), style: panelStyle, children: [
|
|
3642
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
|
|
3315
3643
|
.zenit-layer-manager .zlm-card {
|
|
3316
3644
|
transition: box-shadow 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
|
|
3317
3645
|
box-shadow: 0 6px 16px rgba(15, 23, 42, 0.08);
|
|
@@ -3406,16 +3734,16 @@ var ZenitLayerManager = ({
|
|
|
3406
3734
|
outline-offset: 2px;
|
|
3407
3735
|
}
|
|
3408
3736
|
` }),
|
|
3409
|
-
/* @__PURE__ */ (0,
|
|
3410
|
-
/* @__PURE__ */ (0,
|
|
3411
|
-
/* @__PURE__ */ (0,
|
|
3412
|
-
/* @__PURE__ */ (0,
|
|
3413
|
-
/* @__PURE__ */ (0,
|
|
3737
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: headerStyle, children: [
|
|
3738
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
|
|
3739
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
3740
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontWeight: 800, fontSize: 16, color: "#0f172a" }, children: "Gesti\xF3n de Capas" }),
|
|
3741
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: "#64748b", fontSize: 12 }, children: [
|
|
3414
3742
|
"Mapa #",
|
|
3415
3743
|
map.id
|
|
3416
3744
|
] })
|
|
3417
3745
|
] }),
|
|
3418
|
-
/* @__PURE__ */ (0,
|
|
3746
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3419
3747
|
"button",
|
|
3420
3748
|
{
|
|
3421
3749
|
type: "button",
|
|
@@ -3423,13 +3751,13 @@ var ZenitLayerManager = ({
|
|
|
3423
3751
|
className: "zlm-panel-toggle",
|
|
3424
3752
|
"aria-label": panelVisible ? "Ocultar panel de capas" : "Mostrar panel de capas",
|
|
3425
3753
|
children: [
|
|
3426
|
-
panelVisible ? /* @__PURE__ */ (0,
|
|
3754
|
+
panelVisible ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Eye, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.EyeOff, { size: 16 }),
|
|
3427
3755
|
panelVisible ? "Ocultar" : "Mostrar"
|
|
3428
3756
|
]
|
|
3429
3757
|
}
|
|
3430
3758
|
)
|
|
3431
3759
|
] }),
|
|
3432
|
-
/* @__PURE__ */ (0,
|
|
3760
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3433
3761
|
"div",
|
|
3434
3762
|
{
|
|
3435
3763
|
style: {
|
|
@@ -3442,26 +3770,26 @@ var ZenitLayerManager = ({
|
|
|
3442
3770
|
background: "#f1f5f9"
|
|
3443
3771
|
},
|
|
3444
3772
|
children: [
|
|
3445
|
-
/* @__PURE__ */ (0,
|
|
3773
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3446
3774
|
"button",
|
|
3447
3775
|
{
|
|
3448
3776
|
type: "button",
|
|
3449
3777
|
className: `zlm-tab${activeTab === "layers" ? " is-active" : ""}`,
|
|
3450
3778
|
onClick: () => setActiveTab("layers"),
|
|
3451
3779
|
children: [
|
|
3452
|
-
/* @__PURE__ */ (0,
|
|
3780
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Layers, { size: 16 }),
|
|
3453
3781
|
"Capas"
|
|
3454
3782
|
]
|
|
3455
3783
|
}
|
|
3456
3784
|
),
|
|
3457
|
-
showUploadTab && /* @__PURE__ */ (0,
|
|
3785
|
+
showUploadTab && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3458
3786
|
"button",
|
|
3459
3787
|
{
|
|
3460
3788
|
type: "button",
|
|
3461
3789
|
className: `zlm-tab${activeTab === "upload" ? " is-active" : ""}`,
|
|
3462
3790
|
onClick: () => setActiveTab("upload"),
|
|
3463
3791
|
children: [
|
|
3464
|
-
/* @__PURE__ */ (0,
|
|
3792
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Upload, { size: 16 }),
|
|
3465
3793
|
"Subir"
|
|
3466
3794
|
]
|
|
3467
3795
|
}
|
|
@@ -3470,15 +3798,15 @@ var ZenitLayerManager = ({
|
|
|
3470
3798
|
}
|
|
3471
3799
|
)
|
|
3472
3800
|
] }),
|
|
3473
|
-
panelVisible && /* @__PURE__ */ (0,
|
|
3801
|
+
panelVisible && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
|
|
3474
3802
|
activeTab === "layers" && renderLayerCards(),
|
|
3475
|
-
showUploadTab && activeTab === "upload" && /* @__PURE__ */ (0,
|
|
3803
|
+
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." })
|
|
3476
3804
|
] })
|
|
3477
3805
|
] });
|
|
3478
3806
|
};
|
|
3479
3807
|
|
|
3480
3808
|
// src/react/ZenitFeatureFilterPanel.tsx
|
|
3481
|
-
var
|
|
3809
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
3482
3810
|
var ZenitFeatureFilterPanel = ({
|
|
3483
3811
|
title = "Filtros",
|
|
3484
3812
|
description,
|
|
@@ -3486,7 +3814,7 @@ var ZenitFeatureFilterPanel = ({
|
|
|
3486
3814
|
style,
|
|
3487
3815
|
children
|
|
3488
3816
|
}) => {
|
|
3489
|
-
return /* @__PURE__ */ (0,
|
|
3817
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3490
3818
|
"section",
|
|
3491
3819
|
{
|
|
3492
3820
|
className,
|
|
@@ -3499,26 +3827,26 @@ var ZenitFeatureFilterPanel = ({
|
|
|
3499
3827
|
...style
|
|
3500
3828
|
},
|
|
3501
3829
|
children: [
|
|
3502
|
-
/* @__PURE__ */ (0,
|
|
3503
|
-
/* @__PURE__ */ (0,
|
|
3504
|
-
description && /* @__PURE__ */ (0,
|
|
3830
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("header", { style: { marginBottom: 12 }, children: [
|
|
3831
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { style: { margin: 0, fontSize: 16 }, children: title }),
|
|
3832
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { style: { margin: "6px 0 0", color: "#475569", fontSize: 13 }, children: description })
|
|
3505
3833
|
] }),
|
|
3506
|
-
/* @__PURE__ */ (0,
|
|
3834
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children })
|
|
3507
3835
|
]
|
|
3508
3836
|
}
|
|
3509
3837
|
);
|
|
3510
3838
|
};
|
|
3511
3839
|
|
|
3512
3840
|
// src/react/ai/FloatingChatBox.tsx
|
|
3513
|
-
var
|
|
3514
|
-
var
|
|
3841
|
+
var import_react7 = require("react");
|
|
3842
|
+
var import_react_dom2 = require("react-dom");
|
|
3515
3843
|
|
|
3516
3844
|
// src/react/hooks/use-chat.ts
|
|
3517
|
-
var
|
|
3845
|
+
var import_react6 = require("react");
|
|
3518
3846
|
var useSendMessage = (config) => {
|
|
3519
|
-
const [isLoading, setIsLoading] = (0,
|
|
3520
|
-
const [error, setError] = (0,
|
|
3521
|
-
const send = (0,
|
|
3847
|
+
const [isLoading, setIsLoading] = (0, import_react6.useState)(false);
|
|
3848
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
3849
|
+
const send = (0, import_react6.useCallback)(
|
|
3522
3850
|
async (mapId, request, options) => {
|
|
3523
3851
|
setIsLoading(true);
|
|
3524
3852
|
setError(null);
|
|
@@ -3536,18 +3864,18 @@ var useSendMessage = (config) => {
|
|
|
3536
3864
|
return { sendMessage: send, isLoading, error };
|
|
3537
3865
|
};
|
|
3538
3866
|
var useSendMessageStream = (config) => {
|
|
3539
|
-
const [isStreaming, setIsStreaming] = (0,
|
|
3540
|
-
const [streamingText, setStreamingText] = (0,
|
|
3541
|
-
const [completeResponse, setCompleteResponse] = (0,
|
|
3542
|
-
const [error, setError] = (0,
|
|
3543
|
-
const requestIdRef = (0,
|
|
3544
|
-
const reset = (0,
|
|
3867
|
+
const [isStreaming, setIsStreaming] = (0, import_react6.useState)(false);
|
|
3868
|
+
const [streamingText, setStreamingText] = (0, import_react6.useState)("");
|
|
3869
|
+
const [completeResponse, setCompleteResponse] = (0, import_react6.useState)(null);
|
|
3870
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
3871
|
+
const requestIdRef = (0, import_react6.useRef)(0);
|
|
3872
|
+
const reset = (0, import_react6.useCallback)(() => {
|
|
3545
3873
|
setIsStreaming(false);
|
|
3546
3874
|
setStreamingText("");
|
|
3547
3875
|
setCompleteResponse(null);
|
|
3548
3876
|
setError(null);
|
|
3549
3877
|
}, []);
|
|
3550
|
-
const send = (0,
|
|
3878
|
+
const send = (0, import_react6.useCallback)(
|
|
3551
3879
|
async (mapId, request, options) => {
|
|
3552
3880
|
const requestId = requestIdRef.current + 1;
|
|
3553
3881
|
requestIdRef.current = requestId;
|
|
@@ -3601,7 +3929,7 @@ var useSendMessageStream = (config) => {
|
|
|
3601
3929
|
// src/react/components/MarkdownRenderer.tsx
|
|
3602
3930
|
var import_react_markdown = __toESM(require("react-markdown"));
|
|
3603
3931
|
var import_remark_gfm = __toESM(require("remark-gfm"));
|
|
3604
|
-
var
|
|
3932
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
3605
3933
|
function normalizeAssistantMarkdown(text) {
|
|
3606
3934
|
if (!text || typeof text !== "string") return "";
|
|
3607
3935
|
let normalized = text;
|
|
@@ -3617,28 +3945,28 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3617
3945
|
if (!normalizedContent) {
|
|
3618
3946
|
return null;
|
|
3619
3947
|
}
|
|
3620
|
-
return /* @__PURE__ */ (0,
|
|
3948
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className, style: { wordBreak: "break-word" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3621
3949
|
import_react_markdown.default,
|
|
3622
3950
|
{
|
|
3623
3951
|
remarkPlugins: [import_remark_gfm.default],
|
|
3624
3952
|
components: {
|
|
3625
3953
|
// Headings with proper spacing
|
|
3626
|
-
h1: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3627
|
-
h2: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3628
|
-
h3: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3629
|
-
h4: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3630
|
-
h5: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3631
|
-
h6: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3954
|
+
h1: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { style: { fontSize: "1.5em", fontWeight: 700, marginTop: "1em", marginBottom: "0.5em" }, ...props, children }),
|
|
3955
|
+
h2: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { style: { fontSize: "1.3em", fontWeight: 700, marginTop: "0.9em", marginBottom: "0.45em" }, ...props, children }),
|
|
3956
|
+
h3: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { style: { fontSize: "1.15em", fontWeight: 600, marginTop: "0.75em", marginBottom: "0.4em" }, ...props, children }),
|
|
3957
|
+
h4: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h4", { style: { fontSize: "1.05em", fontWeight: 600, marginTop: "0.6em", marginBottom: "0.35em" }, ...props, children }),
|
|
3958
|
+
h5: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h5", { style: { fontSize: "1em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
|
|
3959
|
+
h6: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h6", { style: { fontSize: "0.95em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
|
|
3632
3960
|
// Paragraphs with comfortable line height
|
|
3633
|
-
p: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3961
|
+
p: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: { marginTop: "0.5em", marginBottom: "0.5em", lineHeight: 1.6 }, ...props, children }),
|
|
3634
3962
|
// Lists with proper indentation
|
|
3635
|
-
ul: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3636
|
-
ol: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3637
|
-
li: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3963
|
+
ul: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
|
|
3964
|
+
ol: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ol", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
|
|
3965
|
+
li: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { style: { marginTop: "0.25em", marginBottom: "0.25em" }, ...props, children }),
|
|
3638
3966
|
// Code blocks
|
|
3639
3967
|
code: ({ inline, children, ...props }) => {
|
|
3640
3968
|
if (inline) {
|
|
3641
|
-
return /* @__PURE__ */ (0,
|
|
3969
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3642
3970
|
"code",
|
|
3643
3971
|
{
|
|
3644
3972
|
style: {
|
|
@@ -3653,7 +3981,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3653
3981
|
}
|
|
3654
3982
|
);
|
|
3655
3983
|
}
|
|
3656
|
-
return /* @__PURE__ */ (0,
|
|
3984
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3657
3985
|
"code",
|
|
3658
3986
|
{
|
|
3659
3987
|
style: {
|
|
@@ -3673,9 +4001,9 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3673
4001
|
);
|
|
3674
4002
|
},
|
|
3675
4003
|
// Pre (code block wrapper)
|
|
3676
|
-
pre: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4004
|
+
pre: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { style: { margin: 0 }, ...props, children }),
|
|
3677
4005
|
// Blockquotes
|
|
3678
|
-
blockquote: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4006
|
+
blockquote: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3679
4007
|
"blockquote",
|
|
3680
4008
|
{
|
|
3681
4009
|
style: {
|
|
@@ -3691,11 +4019,11 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3691
4019
|
}
|
|
3692
4020
|
),
|
|
3693
4021
|
// Strong/bold
|
|
3694
|
-
strong: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4022
|
+
strong: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { style: { fontWeight: 600 }, ...props, children }),
|
|
3695
4023
|
// Emphasis/italic
|
|
3696
|
-
em: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4024
|
+
em: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("em", { style: { fontStyle: "italic" }, ...props, children }),
|
|
3697
4025
|
// Horizontal rule
|
|
3698
|
-
hr: (props) => /* @__PURE__ */ (0,
|
|
4026
|
+
hr: (props) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3699
4027
|
"hr",
|
|
3700
4028
|
{
|
|
3701
4029
|
style: {
|
|
@@ -3708,7 +4036,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3708
4036
|
}
|
|
3709
4037
|
),
|
|
3710
4038
|
// Tables (GFM)
|
|
3711
|
-
table: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4039
|
+
table: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { overflowX: "auto", marginTop: "0.5em", marginBottom: "0.5em" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3712
4040
|
"table",
|
|
3713
4041
|
{
|
|
3714
4042
|
style: {
|
|
@@ -3720,7 +4048,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3720
4048
|
children
|
|
3721
4049
|
}
|
|
3722
4050
|
) }),
|
|
3723
|
-
th: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4051
|
+
th: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3724
4052
|
"th",
|
|
3725
4053
|
{
|
|
3726
4054
|
style: {
|
|
@@ -3734,7 +4062,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3734
4062
|
children
|
|
3735
4063
|
}
|
|
3736
4064
|
),
|
|
3737
|
-
td: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4065
|
+
td: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3738
4066
|
"td",
|
|
3739
4067
|
{
|
|
3740
4068
|
style: {
|
|
@@ -3752,32 +4080,32 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3752
4080
|
};
|
|
3753
4081
|
|
|
3754
4082
|
// src/react/ai/FloatingChatBox.tsx
|
|
3755
|
-
var
|
|
3756
|
-
var ChatIcon = () => /* @__PURE__ */ (0,
|
|
3757
|
-
var CloseIcon = () => /* @__PURE__ */ (0,
|
|
3758
|
-
/* @__PURE__ */ (0,
|
|
3759
|
-
/* @__PURE__ */ (0,
|
|
4083
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
4084
|
+
var ChatIcon = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
|
|
4085
|
+
var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
4086
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
4087
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
3760
4088
|
] });
|
|
3761
|
-
var ExpandIcon = () => /* @__PURE__ */ (0,
|
|
3762
|
-
/* @__PURE__ */ (0,
|
|
3763
|
-
/* @__PURE__ */ (0,
|
|
3764
|
-
/* @__PURE__ */ (0,
|
|
3765
|
-
/* @__PURE__ */ (0,
|
|
4089
|
+
var ExpandIcon = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
4090
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "15 3 21 3 21 9" }),
|
|
4091
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "9 21 3 21 3 15" }),
|
|
4092
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
|
|
4093
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
|
|
3766
4094
|
] });
|
|
3767
|
-
var CollapseIcon = () => /* @__PURE__ */ (0,
|
|
3768
|
-
/* @__PURE__ */ (0,
|
|
3769
|
-
/* @__PURE__ */ (0,
|
|
3770
|
-
/* @__PURE__ */ (0,
|
|
3771
|
-
/* @__PURE__ */ (0,
|
|
4095
|
+
var CollapseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
4096
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "4 14 10 14 10 20" }),
|
|
4097
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "20 10 14 10 14 4" }),
|
|
4098
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
|
|
4099
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
|
|
3772
4100
|
] });
|
|
3773
|
-
var SendIcon = () => /* @__PURE__ */ (0,
|
|
3774
|
-
/* @__PURE__ */ (0,
|
|
3775
|
-
/* @__PURE__ */ (0,
|
|
4101
|
+
var SendIcon = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
4102
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
|
|
4103
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
3776
4104
|
] });
|
|
3777
|
-
var LayersIcon = () => /* @__PURE__ */ (0,
|
|
3778
|
-
/* @__PURE__ */ (0,
|
|
3779
|
-
/* @__PURE__ */ (0,
|
|
3780
|
-
/* @__PURE__ */ (0,
|
|
4105
|
+
var LayersIcon = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
4106
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
|
|
4107
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "2 17 12 22 22 17" }),
|
|
4108
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "2 12 12 17 22 12" })
|
|
3781
4109
|
] });
|
|
3782
4110
|
var styles = {
|
|
3783
4111
|
root: {
|
|
@@ -3786,8 +4114,8 @@ var styles = {
|
|
|
3786
4114
|
// Floating button (closed state - wide with text, open state - circular with X)
|
|
3787
4115
|
floatingButton: {
|
|
3788
4116
|
position: "fixed",
|
|
3789
|
-
bottom:
|
|
3790
|
-
right:
|
|
4117
|
+
bottom: 16,
|
|
4118
|
+
right: 16,
|
|
3791
4119
|
borderRadius: "999px",
|
|
3792
4120
|
border: "none",
|
|
3793
4121
|
cursor: "pointer",
|
|
@@ -3797,30 +4125,30 @@ var styles = {
|
|
|
3797
4125
|
display: "flex",
|
|
3798
4126
|
alignItems: "center",
|
|
3799
4127
|
justifyContent: "center",
|
|
3800
|
-
fontSize:
|
|
4128
|
+
fontSize: 14,
|
|
3801
4129
|
fontWeight: 600,
|
|
3802
4130
|
zIndex: 99999,
|
|
3803
4131
|
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
|
|
3804
4132
|
},
|
|
3805
4133
|
floatingButtonClosed: {
|
|
3806
|
-
padding: "
|
|
4134
|
+
padding: "12px 20px",
|
|
3807
4135
|
gap: 8
|
|
3808
4136
|
},
|
|
3809
4137
|
floatingButtonOpen: {
|
|
3810
|
-
width:
|
|
3811
|
-
height:
|
|
4138
|
+
width: 52,
|
|
4139
|
+
height: 52,
|
|
3812
4140
|
padding: 0
|
|
3813
4141
|
},
|
|
3814
4142
|
floatingButtonMobile: {
|
|
3815
|
-
width:
|
|
3816
|
-
height:
|
|
4143
|
+
width: 52,
|
|
4144
|
+
height: 52,
|
|
3817
4145
|
padding: 0
|
|
3818
4146
|
},
|
|
3819
4147
|
// Panel (expandable)
|
|
3820
4148
|
panel: {
|
|
3821
4149
|
position: "fixed",
|
|
3822
|
-
bottom:
|
|
3823
|
-
right:
|
|
4150
|
+
bottom: 80,
|
|
4151
|
+
right: 16,
|
|
3824
4152
|
background: "#fff",
|
|
3825
4153
|
borderRadius: 16,
|
|
3826
4154
|
boxShadow: "0 20px 60px rgba(15, 23, 42, 0.3), 0 0 0 1px rgba(15, 23, 42, 0.05)",
|
|
@@ -3831,16 +4159,16 @@ var styles = {
|
|
|
3831
4159
|
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
|
|
3832
4160
|
},
|
|
3833
4161
|
panelNormal: {
|
|
3834
|
-
width:
|
|
3835
|
-
height:
|
|
4162
|
+
width: 360,
|
|
4163
|
+
height: 520
|
|
3836
4164
|
},
|
|
3837
4165
|
panelExpanded: {
|
|
3838
|
-
width:
|
|
3839
|
-
height:
|
|
4166
|
+
width: 480,
|
|
4167
|
+
height: 640
|
|
3840
4168
|
},
|
|
3841
4169
|
// Header with green gradient
|
|
3842
4170
|
header: {
|
|
3843
|
-
padding: "16px
|
|
4171
|
+
padding: "14px 16px",
|
|
3844
4172
|
background: "linear-gradient(135deg, #10b981, #059669)",
|
|
3845
4173
|
color: "#fff",
|
|
3846
4174
|
display: "flex",
|
|
@@ -3849,7 +4177,7 @@ var styles = {
|
|
|
3849
4177
|
},
|
|
3850
4178
|
title: {
|
|
3851
4179
|
margin: 0,
|
|
3852
|
-
fontSize:
|
|
4180
|
+
fontSize: 15,
|
|
3853
4181
|
fontWeight: 600,
|
|
3854
4182
|
letterSpacing: "-0.01em"
|
|
3855
4183
|
},
|
|
@@ -3862,8 +4190,8 @@ var styles = {
|
|
|
3862
4190
|
border: "none",
|
|
3863
4191
|
background: "rgba(255, 255, 255, 0.15)",
|
|
3864
4192
|
color: "#fff",
|
|
3865
|
-
width:
|
|
3866
|
-
height:
|
|
4193
|
+
width: 30,
|
|
4194
|
+
height: 30,
|
|
3867
4195
|
borderRadius: 8,
|
|
3868
4196
|
cursor: "pointer",
|
|
3869
4197
|
display: "flex",
|
|
@@ -3874,7 +4202,7 @@ var styles = {
|
|
|
3874
4202
|
// Messages area
|
|
3875
4203
|
messages: {
|
|
3876
4204
|
flex: 1,
|
|
3877
|
-
padding: "
|
|
4205
|
+
padding: "16px",
|
|
3878
4206
|
overflowY: "auto",
|
|
3879
4207
|
background: "#f8fafc",
|
|
3880
4208
|
display: "flex",
|
|
@@ -3889,10 +4217,10 @@ var styles = {
|
|
|
3889
4217
|
},
|
|
3890
4218
|
messageBubble: {
|
|
3891
4219
|
maxWidth: "85%",
|
|
3892
|
-
padding: "12px
|
|
4220
|
+
padding: "10px 12px",
|
|
3893
4221
|
borderRadius: 16,
|
|
3894
4222
|
lineHeight: 1.5,
|
|
3895
|
-
fontSize:
|
|
4223
|
+
fontSize: 13,
|
|
3896
4224
|
whiteSpace: "pre-wrap",
|
|
3897
4225
|
wordBreak: "break-word"
|
|
3898
4226
|
},
|
|
@@ -4006,7 +4334,7 @@ var styles = {
|
|
|
4006
4334
|
// Input area
|
|
4007
4335
|
inputWrapper: {
|
|
4008
4336
|
borderTop: "1px solid #e2e8f0",
|
|
4009
|
-
padding: "14px
|
|
4337
|
+
padding: "10px 14px",
|
|
4010
4338
|
display: "flex",
|
|
4011
4339
|
gap: 10,
|
|
4012
4340
|
alignItems: "flex-end",
|
|
@@ -4017,8 +4345,8 @@ var styles = {
|
|
|
4017
4345
|
resize: "none",
|
|
4018
4346
|
borderRadius: 12,
|
|
4019
4347
|
border: "1.5px solid #cbd5e1",
|
|
4020
|
-
padding: "10px
|
|
4021
|
-
fontSize:
|
|
4348
|
+
padding: "8px 10px",
|
|
4349
|
+
fontSize: 13,
|
|
4022
4350
|
fontFamily: "inherit",
|
|
4023
4351
|
lineHeight: 1.4,
|
|
4024
4352
|
transition: "border-color 0.2s"
|
|
@@ -4030,18 +4358,18 @@ var styles = {
|
|
|
4030
4358
|
sendButton: {
|
|
4031
4359
|
borderRadius: 12,
|
|
4032
4360
|
border: "none",
|
|
4033
|
-
padding: "
|
|
4361
|
+
padding: "8px 12px",
|
|
4034
4362
|
background: "linear-gradient(135deg, #10b981, #059669)",
|
|
4035
4363
|
color: "#fff",
|
|
4036
4364
|
cursor: "pointer",
|
|
4037
|
-
fontSize:
|
|
4365
|
+
fontSize: 13,
|
|
4038
4366
|
fontWeight: 600,
|
|
4039
4367
|
display: "flex",
|
|
4040
4368
|
alignItems: "center",
|
|
4041
4369
|
justifyContent: "center",
|
|
4042
4370
|
transition: "opacity 0.2s, transform 0.2s",
|
|
4043
|
-
minWidth:
|
|
4044
|
-
height:
|
|
4371
|
+
minWidth: 40,
|
|
4372
|
+
height: 40
|
|
4045
4373
|
},
|
|
4046
4374
|
// Status messages
|
|
4047
4375
|
statusNote: {
|
|
@@ -4071,42 +4399,42 @@ var FloatingChatBox = ({
|
|
|
4071
4399
|
open: openProp
|
|
4072
4400
|
}) => {
|
|
4073
4401
|
const isControlled = openProp !== void 0;
|
|
4074
|
-
const [internalOpen, setInternalOpen] = (0,
|
|
4402
|
+
const [internalOpen, setInternalOpen] = (0, import_react7.useState)(false);
|
|
4075
4403
|
const open = isControlled ? openProp : internalOpen;
|
|
4076
|
-
const setOpen = (0,
|
|
4404
|
+
const setOpen = (0, import_react7.useCallback)((value) => {
|
|
4077
4405
|
const newValue = typeof value === "function" ? value(open) : value;
|
|
4078
4406
|
if (!isControlled) {
|
|
4079
4407
|
setInternalOpen(newValue);
|
|
4080
4408
|
}
|
|
4081
4409
|
onOpenChange?.(newValue);
|
|
4082
4410
|
}, [isControlled, open, onOpenChange]);
|
|
4083
|
-
const [expanded, setExpanded] = (0,
|
|
4084
|
-
const [messages, setMessages] = (0,
|
|
4085
|
-
const [inputValue, setInputValue] = (0,
|
|
4086
|
-
const [conversationId, setConversationId] = (0,
|
|
4087
|
-
const [errorMessage, setErrorMessage] = (0,
|
|
4088
|
-
const [isFocused, setIsFocused] = (0,
|
|
4089
|
-
const [isMobile, setIsMobile] = (0,
|
|
4090
|
-
const messagesEndRef = (0,
|
|
4091
|
-
const messagesContainerRef = (0,
|
|
4092
|
-
const chatBoxRef = (0,
|
|
4093
|
-
const chatConfig = (0,
|
|
4411
|
+
const [expanded, setExpanded] = (0, import_react7.useState)(false);
|
|
4412
|
+
const [messages, setMessages] = (0, import_react7.useState)([]);
|
|
4413
|
+
const [inputValue, setInputValue] = (0, import_react7.useState)("");
|
|
4414
|
+
const [conversationId, setConversationId] = (0, import_react7.useState)();
|
|
4415
|
+
const [errorMessage, setErrorMessage] = (0, import_react7.useState)(null);
|
|
4416
|
+
const [isFocused, setIsFocused] = (0, import_react7.useState)(false);
|
|
4417
|
+
const [isMobile, setIsMobile] = (0, import_react7.useState)(false);
|
|
4418
|
+
const messagesEndRef = (0, import_react7.useRef)(null);
|
|
4419
|
+
const messagesContainerRef = (0, import_react7.useRef)(null);
|
|
4420
|
+
const chatBoxRef = (0, import_react7.useRef)(null);
|
|
4421
|
+
const chatConfig = (0, import_react7.useMemo)(() => {
|
|
4094
4422
|
if (!baseUrl) return void 0;
|
|
4095
4423
|
return { baseUrl, accessToken, getAccessToken };
|
|
4096
4424
|
}, [accessToken, baseUrl, getAccessToken]);
|
|
4097
4425
|
const { sendMessage: sendMessage2, isStreaming, streamingText, completeResponse } = useSendMessageStream(chatConfig);
|
|
4098
4426
|
const canSend = Boolean(mapId) && Boolean(baseUrl) && inputValue.trim().length > 0 && !isStreaming;
|
|
4099
|
-
(0,
|
|
4427
|
+
(0, import_react7.useEffect)(() => {
|
|
4100
4428
|
if (open && isMobile) {
|
|
4101
4429
|
setExpanded(true);
|
|
4102
4430
|
}
|
|
4103
4431
|
}, [open, isMobile]);
|
|
4104
|
-
const scrollToBottom = (0,
|
|
4432
|
+
const scrollToBottom = (0, import_react7.useCallback)(() => {
|
|
4105
4433
|
if (messagesEndRef.current) {
|
|
4106
4434
|
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
4107
4435
|
}
|
|
4108
4436
|
}, []);
|
|
4109
|
-
(0,
|
|
4437
|
+
(0, import_react7.useEffect)(() => {
|
|
4110
4438
|
if (open && messages.length === 0) {
|
|
4111
4439
|
setMessages([
|
|
4112
4440
|
{
|
|
@@ -4117,10 +4445,10 @@ var FloatingChatBox = ({
|
|
|
4117
4445
|
]);
|
|
4118
4446
|
}
|
|
4119
4447
|
}, [open, messages.length]);
|
|
4120
|
-
(0,
|
|
4448
|
+
(0, import_react7.useEffect)(() => {
|
|
4121
4449
|
scrollToBottom();
|
|
4122
4450
|
}, [messages, streamingText, scrollToBottom]);
|
|
4123
|
-
(0,
|
|
4451
|
+
(0, import_react7.useEffect)(() => {
|
|
4124
4452
|
if (!open) return;
|
|
4125
4453
|
if (isMobile && expanded) return;
|
|
4126
4454
|
const handleClickOutside = (event) => {
|
|
@@ -4133,7 +4461,7 @@ var FloatingChatBox = ({
|
|
|
4133
4461
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
4134
4462
|
};
|
|
4135
4463
|
}, [open, isMobile, expanded]);
|
|
4136
|
-
(0,
|
|
4464
|
+
(0, import_react7.useEffect)(() => {
|
|
4137
4465
|
if (typeof window === "undefined") return;
|
|
4138
4466
|
const mediaQuery = window.matchMedia("(max-width: 768px)");
|
|
4139
4467
|
const updateMobile = () => setIsMobile(mediaQuery.matches);
|
|
@@ -4151,7 +4479,7 @@ var FloatingChatBox = ({
|
|
|
4151
4479
|
}
|
|
4152
4480
|
};
|
|
4153
4481
|
}, []);
|
|
4154
|
-
(0,
|
|
4482
|
+
(0, import_react7.useEffect)(() => {
|
|
4155
4483
|
if (typeof document === "undefined") return;
|
|
4156
4484
|
if (!open || !isMobile) return;
|
|
4157
4485
|
document.body.style.overflow = "hidden";
|
|
@@ -4159,10 +4487,10 @@ var FloatingChatBox = ({
|
|
|
4159
4487
|
document.body.style.overflow = "";
|
|
4160
4488
|
};
|
|
4161
4489
|
}, [open, isMobile]);
|
|
4162
|
-
const addMessage = (0,
|
|
4490
|
+
const addMessage = (0, import_react7.useCallback)((message) => {
|
|
4163
4491
|
setMessages((prev) => [...prev, message]);
|
|
4164
4492
|
}, []);
|
|
4165
|
-
const handleSend = (0,
|
|
4493
|
+
const handleSend = (0, import_react7.useCallback)(async () => {
|
|
4166
4494
|
if (!mapId) {
|
|
4167
4495
|
setErrorMessage("Selecciona un mapa para usar el asistente.");
|
|
4168
4496
|
return;
|
|
@@ -4197,11 +4525,11 @@ var FloatingChatBox = ({
|
|
|
4197
4525
|
response
|
|
4198
4526
|
});
|
|
4199
4527
|
} catch (error) {
|
|
4200
|
-
setErrorMessage(
|
|
4528
|
+
setErrorMessage("Ocurri\xF3 un error al generar la respuesta.");
|
|
4201
4529
|
addMessage({
|
|
4202
4530
|
id: `error-${Date.now()}`,
|
|
4203
4531
|
role: "assistant",
|
|
4204
|
-
content:
|
|
4532
|
+
content: "\u274C Ocurri\xF3 un error al generar la respuesta."
|
|
4205
4533
|
});
|
|
4206
4534
|
}
|
|
4207
4535
|
}, [
|
|
@@ -4215,7 +4543,7 @@ var FloatingChatBox = ({
|
|
|
4215
4543
|
sendMessage2,
|
|
4216
4544
|
userId
|
|
4217
4545
|
]);
|
|
4218
|
-
const handleKeyDown = (0,
|
|
4546
|
+
const handleKeyDown = (0, import_react7.useCallback)(
|
|
4219
4547
|
(event) => {
|
|
4220
4548
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
4221
4549
|
event.preventDefault();
|
|
@@ -4226,20 +4554,20 @@ var FloatingChatBox = ({
|
|
|
4226
4554
|
},
|
|
4227
4555
|
[canSend, handleSend]
|
|
4228
4556
|
);
|
|
4229
|
-
const handleFollowUpClick = (0,
|
|
4557
|
+
const handleFollowUpClick = (0, import_react7.useCallback)((question) => {
|
|
4230
4558
|
setInputValue(question);
|
|
4231
4559
|
}, []);
|
|
4232
4560
|
const renderMetadata = (response) => {
|
|
4233
4561
|
if (!response?.metadata) return null;
|
|
4234
4562
|
const referencedLayers = response.metadata.referencedLayers;
|
|
4235
4563
|
if (!referencedLayers || referencedLayers.length === 0) return null;
|
|
4236
|
-
return /* @__PURE__ */ (0,
|
|
4237
|
-
/* @__PURE__ */ (0,
|
|
4238
|
-
/* @__PURE__ */ (0,
|
|
4564
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.metadataSection, children: [
|
|
4565
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.metadataTitle, children: [
|
|
4566
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LayersIcon, {}),
|
|
4239
4567
|
"Capas Analizadas"
|
|
4240
4568
|
] }),
|
|
4241
|
-
/* @__PURE__ */ (0,
|
|
4242
|
-
/* @__PURE__ */ (0,
|
|
4569
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { style: styles.metadataList, children: referencedLayers.map((layer, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("li", { style: styles.metadataItem, children: [
|
|
4570
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: layer.layerName }),
|
|
4243
4571
|
" (",
|
|
4244
4572
|
layer.featureCount,
|
|
4245
4573
|
" ",
|
|
@@ -4248,7 +4576,7 @@ var FloatingChatBox = ({
|
|
|
4248
4576
|
] }, index)) })
|
|
4249
4577
|
] });
|
|
4250
4578
|
};
|
|
4251
|
-
const handleActionClick = (0,
|
|
4579
|
+
const handleActionClick = (0, import_react7.useCallback)((action) => {
|
|
4252
4580
|
if (isStreaming) return;
|
|
4253
4581
|
setOpen(false);
|
|
4254
4582
|
requestAnimationFrame(() => {
|
|
@@ -4257,9 +4585,9 @@ var FloatingChatBox = ({
|
|
|
4257
4585
|
}, [isStreaming, setOpen, onActionClick]);
|
|
4258
4586
|
const renderActions = (response) => {
|
|
4259
4587
|
if (!response?.suggestedActions?.length) return null;
|
|
4260
|
-
return /* @__PURE__ */ (0,
|
|
4261
|
-
/* @__PURE__ */ (0,
|
|
4262
|
-
/* @__PURE__ */ (0,
|
|
4588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.actionsSection, children: [
|
|
4589
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.sectionLabel, children: "Acciones Sugeridas" }),
|
|
4590
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.actionsGrid, children: response.suggestedActions.map((action, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4263
4591
|
"button",
|
|
4264
4592
|
{
|
|
4265
4593
|
type: "button",
|
|
@@ -4290,9 +4618,9 @@ var FloatingChatBox = ({
|
|
|
4290
4618
|
};
|
|
4291
4619
|
const renderFollowUps = (response) => {
|
|
4292
4620
|
if (!response?.followUpQuestions?.length) return null;
|
|
4293
|
-
return /* @__PURE__ */ (0,
|
|
4294
|
-
/* @__PURE__ */ (0,
|
|
4295
|
-
/* @__PURE__ */ (0,
|
|
4621
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.actionsSection, children: [
|
|
4622
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.sectionLabel, children: "Preguntas Relacionadas" }),
|
|
4623
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: response.followUpQuestions.map((question, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4296
4624
|
"button",
|
|
4297
4625
|
{
|
|
4298
4626
|
type: "button",
|
|
@@ -4321,8 +4649,8 @@ var FloatingChatBox = ({
|
|
|
4321
4649
|
)) })
|
|
4322
4650
|
] });
|
|
4323
4651
|
};
|
|
4324
|
-
const chatContent = /* @__PURE__ */ (0,
|
|
4325
|
-
/* @__PURE__ */ (0,
|
|
4652
|
+
const chatContent = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.root, children: [
|
|
4653
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `
|
|
4326
4654
|
@keyframes zenitBlink {
|
|
4327
4655
|
0%, 49% { opacity: 1; }
|
|
4328
4656
|
50%, 100% { opacity: 0; }
|
|
@@ -4365,11 +4693,13 @@ var FloatingChatBox = ({
|
|
|
4365
4693
|
@media (max-width: 768px) {
|
|
4366
4694
|
.zenit-chat-panel.zenit-chat-panel--fullscreen {
|
|
4367
4695
|
position: fixed !important;
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
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;
|
|
4373
4703
|
border-radius: 0 !important;
|
|
4374
4704
|
display: flex !important;
|
|
4375
4705
|
flex-direction: column !important;
|
|
@@ -4392,7 +4722,7 @@ var FloatingChatBox = ({
|
|
|
4392
4722
|
}
|
|
4393
4723
|
}
|
|
4394
4724
|
` }),
|
|
4395
|
-
open && /* @__PURE__ */ (0,
|
|
4725
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
4396
4726
|
"div",
|
|
4397
4727
|
{
|
|
4398
4728
|
ref: chatBoxRef,
|
|
@@ -4402,10 +4732,10 @@ var FloatingChatBox = ({
|
|
|
4402
4732
|
...expanded ? styles.panelExpanded : styles.panelNormal
|
|
4403
4733
|
},
|
|
4404
4734
|
children: [
|
|
4405
|
-
/* @__PURE__ */ (0,
|
|
4406
|
-
/* @__PURE__ */ (0,
|
|
4407
|
-
/* @__PURE__ */ (0,
|
|
4408
|
-
/* @__PURE__ */ (0,
|
|
4735
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("header", { style: styles.header, children: [
|
|
4736
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { style: styles.title, children: "Asistente Zenit AI" }),
|
|
4737
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.headerButtons, children: [
|
|
4738
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4409
4739
|
"button",
|
|
4410
4740
|
{
|
|
4411
4741
|
type: "button",
|
|
@@ -4418,10 +4748,10 @@ var FloatingChatBox = ({
|
|
|
4418
4748
|
e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
|
|
4419
4749
|
},
|
|
4420
4750
|
"aria-label": expanded ? "Contraer" : "Expandir",
|
|
4421
|
-
children: expanded ? /* @__PURE__ */ (0,
|
|
4751
|
+
children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CollapseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ExpandIcon, {})
|
|
4422
4752
|
}
|
|
4423
4753
|
),
|
|
4424
|
-
/* @__PURE__ */ (0,
|
|
4754
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4425
4755
|
"button",
|
|
4426
4756
|
{
|
|
4427
4757
|
type: "button",
|
|
@@ -4434,20 +4764,20 @@ var FloatingChatBox = ({
|
|
|
4434
4764
|
e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
|
|
4435
4765
|
},
|
|
4436
4766
|
"aria-label": "Cerrar",
|
|
4437
|
-
children: /* @__PURE__ */ (0,
|
|
4767
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {})
|
|
4438
4768
|
}
|
|
4439
4769
|
)
|
|
4440
4770
|
] })
|
|
4441
4771
|
] }),
|
|
4442
|
-
/* @__PURE__ */ (0,
|
|
4443
|
-
messages.map((message) => /* @__PURE__ */ (0,
|
|
4772
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { ref: messagesContainerRef, className: "zenit-ai-body", style: styles.messages, children: [
|
|
4773
|
+
messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4444
4774
|
"div",
|
|
4445
4775
|
{
|
|
4446
4776
|
style: {
|
|
4447
4777
|
...styles.messageWrapper,
|
|
4448
4778
|
alignItems: message.role === "user" ? "flex-end" : "flex-start"
|
|
4449
4779
|
},
|
|
4450
|
-
children: /* @__PURE__ */ (0,
|
|
4780
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
4451
4781
|
"div",
|
|
4452
4782
|
{
|
|
4453
4783
|
style: {
|
|
@@ -4455,7 +4785,7 @@ var FloatingChatBox = ({
|
|
|
4455
4785
|
...message.role === "user" ? styles.userMessage : styles.assistantMessage
|
|
4456
4786
|
},
|
|
4457
4787
|
children: [
|
|
4458
|
-
message.role === "assistant" ? /* @__PURE__ */ (0,
|
|
4788
|
+
message.role === "assistant" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MarkdownRenderer, { content: message.content }) : message.content,
|
|
4459
4789
|
message.role === "assistant" && renderMetadata(message.response),
|
|
4460
4790
|
message.role === "assistant" && renderActions(message.response),
|
|
4461
4791
|
message.role === "assistant" && renderFollowUps(message.response)
|
|
@@ -4465,39 +4795,39 @@ var FloatingChatBox = ({
|
|
|
4465
4795
|
},
|
|
4466
4796
|
message.id
|
|
4467
4797
|
)),
|
|
4468
|
-
isStreaming && /* @__PURE__ */ (0,
|
|
4798
|
+
isStreaming && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4469
4799
|
"div",
|
|
4470
4800
|
{
|
|
4471
4801
|
style: {
|
|
4472
4802
|
...styles.messageWrapper,
|
|
4473
4803
|
alignItems: "flex-start"
|
|
4474
4804
|
},
|
|
4475
|
-
children: /* @__PURE__ */ (0,
|
|
4805
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4476
4806
|
"div",
|
|
4477
4807
|
{
|
|
4478
4808
|
style: {
|
|
4479
4809
|
...styles.messageBubble,
|
|
4480
4810
|
...styles.assistantMessage
|
|
4481
4811
|
},
|
|
4482
|
-
children: streamingText ? /* @__PURE__ */ (0,
|
|
4483
|
-
/* @__PURE__ */ (0,
|
|
4484
|
-
/* @__PURE__ */ (0,
|
|
4485
|
-
] }) : /* @__PURE__ */ (0,
|
|
4486
|
-
/* @__PURE__ */ (0,
|
|
4487
|
-
/* @__PURE__ */ (0,
|
|
4488
|
-
/* @__PURE__ */ (0,
|
|
4489
|
-
/* @__PURE__ */ (0,
|
|
4490
|
-
/* @__PURE__ */ (0,
|
|
4812
|
+
children: streamingText ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4813
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MarkdownRenderer, { content: streamingText }),
|
|
4814
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.cursor })
|
|
4815
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.thinkingText, children: [
|
|
4816
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Pensando" }),
|
|
4817
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.typingIndicator, children: [
|
|
4818
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
|
|
4819
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
|
|
4820
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot })
|
|
4491
4821
|
] })
|
|
4492
4822
|
] })
|
|
4493
4823
|
}
|
|
4494
4824
|
)
|
|
4495
4825
|
}
|
|
4496
4826
|
),
|
|
4497
|
-
/* @__PURE__ */ (0,
|
|
4827
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: messagesEndRef })
|
|
4498
4828
|
] }),
|
|
4499
|
-
/* @__PURE__ */ (0,
|
|
4500
|
-
/* @__PURE__ */ (0,
|
|
4829
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "zenit-ai-input-area", style: styles.inputWrapper, children: [
|
|
4830
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4501
4831
|
"textarea",
|
|
4502
4832
|
{
|
|
4503
4833
|
style: {
|
|
@@ -4514,7 +4844,7 @@ var FloatingChatBox = ({
|
|
|
4514
4844
|
disabled: !mapId || !baseUrl || isStreaming
|
|
4515
4845
|
}
|
|
4516
4846
|
),
|
|
4517
|
-
/* @__PURE__ */ (0,
|
|
4847
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4518
4848
|
"button",
|
|
4519
4849
|
{
|
|
4520
4850
|
type: "button",
|
|
@@ -4523,36 +4853,38 @@ var FloatingChatBox = ({
|
|
|
4523
4853
|
onClick: () => void handleSend(),
|
|
4524
4854
|
disabled: !canSend,
|
|
4525
4855
|
"aria-label": "Enviar mensaje",
|
|
4526
|
-
children: /* @__PURE__ */ (0,
|
|
4856
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SendIcon, {})
|
|
4527
4857
|
}
|
|
4528
4858
|
)
|
|
4529
4859
|
] }),
|
|
4530
|
-
errorMessage && /* @__PURE__ */ (0,
|
|
4531
|
-
|
|
4532
|
-
!
|
|
4860
|
+
errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.errorText, children: errorMessage }),
|
|
4861
|
+
isStreaming && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.statusNote, children: "Generando sugerencias..." }),
|
|
4862
|
+
!mapId && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.statusNote, children: "Selecciona un mapa para usar el asistente" }),
|
|
4863
|
+
!baseUrl && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.statusNote, children: "Configura la baseUrl del SDK" })
|
|
4533
4864
|
]
|
|
4534
4865
|
}
|
|
4535
4866
|
),
|
|
4536
|
-
!(hideButton && !open) && /* @__PURE__ */ (0,
|
|
4867
|
+
!(hideButton && !open) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4537
4868
|
"button",
|
|
4538
4869
|
{
|
|
4539
4870
|
type: "button",
|
|
4540
4871
|
className: `zenit-ai-button ${open ? "open" : ""}${open && isMobile ? " zenit-ai-button--hidden-mobile" : ""}`,
|
|
4541
4872
|
style: {
|
|
4542
4873
|
...styles.floatingButton,
|
|
4543
|
-
...open ? styles.floatingButtonOpen : isMobile ? styles.floatingButtonMobile : styles.floatingButtonClosed
|
|
4874
|
+
...open ? styles.floatingButtonOpen : isMobile ? styles.floatingButtonMobile : styles.floatingButtonClosed,
|
|
4875
|
+
zIndex: open ? 100001 : 99999
|
|
4544
4876
|
},
|
|
4545
4877
|
onClick: () => setOpen((prev) => !prev),
|
|
4546
4878
|
"aria-label": open ? "Cerrar asistente" : "Abrir asistente Zenit AI",
|
|
4547
|
-
children: open ? /* @__PURE__ */ (0,
|
|
4548
|
-
/* @__PURE__ */ (0,
|
|
4549
|
-
!isMobile && /* @__PURE__ */ (0,
|
|
4879
|
+
children: open ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4880
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChatIcon, {}),
|
|
4881
|
+
!isMobile && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Asistente IA" })
|
|
4550
4882
|
] })
|
|
4551
4883
|
}
|
|
4552
4884
|
)
|
|
4553
4885
|
] });
|
|
4554
4886
|
if (typeof document !== "undefined") {
|
|
4555
|
-
return (0,
|
|
4887
|
+
return (0, import_react_dom2.createPortal)(chatContent, document.body);
|
|
4556
4888
|
}
|
|
4557
4889
|
return chatContent;
|
|
4558
4890
|
};
|
|
@@ -4603,12 +4935,15 @@ var FloatingChatBox = ({
|
|
|
4603
4935
|
getZoomOpacityFactor,
|
|
4604
4936
|
initLayerStates,
|
|
4605
4937
|
isPolygonLayer,
|
|
4938
|
+
mergeFilters,
|
|
4606
4939
|
normalizeBbox,
|
|
4940
|
+
normalizeFilters,
|
|
4607
4941
|
normalizeMapCenter,
|
|
4608
4942
|
normalizeMapLayers,
|
|
4609
4943
|
resetOverrides,
|
|
4610
4944
|
resolveLayerAccent,
|
|
4611
4945
|
resolveLayerStrategy,
|
|
4946
|
+
resolveRuntimeConfig,
|
|
4612
4947
|
sendMessage,
|
|
4613
4948
|
sendMessageStream,
|
|
4614
4949
|
shouldSkipGeojsonDownload,
|