zenit-sdk 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/{chunk-52CLFD4L.mjs → chunk-PCTRVN4O.mjs} +1075 -1004
- package/dist/chunk-PCTRVN4O.mjs.map +1 -0
- package/dist/{index-kGwfqTc_.d.mts → index-DvcYGhqj.d.mts} +70 -4
- package/dist/{index-kGwfqTc_.d.ts → index-DvcYGhqj.d.ts} +70 -4
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1218 -1026
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +119 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +1077 -1006
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1 -1
- package/package.json +10 -7
- package/dist/chunk-52CLFD4L.mjs.map +0 -1
package/dist/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,582 +1584,786 @@ 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 (!geojson) return null;
|
|
1476
|
-
if (!Array.isArray(geojson.features) || geojson.features.length === 0) return null;
|
|
1477
|
-
const coords = [];
|
|
1478
|
-
const collect = (candidate) => {
|
|
1479
|
-
if (!Array.isArray(candidate)) return;
|
|
1480
|
-
if (candidate.length === 2 && typeof candidate[0] === "number" && typeof candidate[1] === "number") {
|
|
1481
|
-
coords.push([candidate[0], candidate[1]]);
|
|
1482
|
-
return;
|
|
1483
|
-
}
|
|
1484
|
-
candidate.forEach((entry) => collect(entry));
|
|
1485
|
-
};
|
|
1486
|
-
geojson.features.forEach((feature) => {
|
|
1487
|
-
collect(feature.geometry?.coordinates);
|
|
1488
|
-
});
|
|
1489
|
-
if (coords.length === 0) return null;
|
|
1490
|
-
const [firstLon, firstLat] = coords[0];
|
|
1491
|
-
const bbox = { minLon: firstLon, minLat: firstLat, maxLon: firstLon, maxLat: firstLat };
|
|
1492
|
-
coords.forEach(([lon, lat]) => {
|
|
1493
|
-
bbox.minLon = Math.min(bbox.minLon, lon);
|
|
1494
|
-
bbox.minLat = Math.min(bbox.minLat, lat);
|
|
1495
|
-
bbox.maxLon = Math.max(bbox.maxLon, lon);
|
|
1496
|
-
bbox.maxLat = Math.max(bbox.maxLat, lat);
|
|
1497
|
-
});
|
|
1498
|
-
return bbox;
|
|
1499
|
-
}
|
|
1500
|
-
function mergeBBoxes(bboxes) {
|
|
1501
|
-
const valid = bboxes.filter((bbox) => !!bbox);
|
|
1502
|
-
if (valid.length === 0) return null;
|
|
1503
|
-
const first = valid[0];
|
|
1504
|
-
return valid.slice(1).reduce(
|
|
1505
|
-
(acc, bbox) => ({
|
|
1506
|
-
minLon: Math.min(acc.minLon, bbox.minLon),
|
|
1507
|
-
minLat: Math.min(acc.minLat, bbox.minLat),
|
|
1508
|
-
maxLon: Math.max(acc.maxLon, bbox.maxLon),
|
|
1509
|
-
maxLat: Math.max(acc.maxLat, bbox.maxLat)
|
|
1510
|
-
}),
|
|
1511
|
-
{ ...first }
|
|
1512
|
-
);
|
|
1513
|
-
}
|
|
1514
|
-
function isRecord(value) {
|
|
1515
|
-
return typeof value === "object" && value !== null;
|
|
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;
|
|
1516
1595
|
}
|
|
1517
|
-
function
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
if (!Array.isArray(features)) return false;
|
|
1521
|
-
const type = value.type;
|
|
1522
|
-
return type === void 0 || type === "FeatureCollection";
|
|
1596
|
+
function isPointGeometry(feature) {
|
|
1597
|
+
const geometryType = getGeometryType(feature);
|
|
1598
|
+
return geometryType !== null && POINT_GEOMETRY_TYPES.has(geometryType);
|
|
1523
1599
|
}
|
|
1524
|
-
function
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
return isGeoJsonFeatureCollection(data) ? data : null;
|
|
1528
|
-
}
|
|
1529
|
-
return isGeoJsonFeatureCollection(value) ? value : null;
|
|
1600
|
+
function isNonPointGeometry(feature) {
|
|
1601
|
+
const geometryType = getGeometryType(feature);
|
|
1602
|
+
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
1530
1603
|
}
|
|
1531
|
-
function
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1604
|
+
function buildFeatureCollection(features) {
|
|
1605
|
+
return {
|
|
1606
|
+
type: "FeatureCollection",
|
|
1607
|
+
features
|
|
1608
|
+
};
|
|
1535
1609
|
}
|
|
1536
|
-
|
|
1537
|
-
|
|
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
|
+
};
|
|
1538
1727
|
}
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
var
|
|
1728
|
+
|
|
1729
|
+
// src/react/map/map-utils.ts
|
|
1730
|
+
var import_leaflet2 = __toESM(require("leaflet"));
|
|
1542
1731
|
var POPUP_STYLE_ID = "zenit-leaflet-popup-styles";
|
|
1543
|
-
var
|
|
1544
|
-
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 };
|
|
1545
1736
|
var ZENIT_LEAFLET_POPUP_STYLES = `
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
/* Main popup wrapper */
|
|
1549
|
-
.zenit-leaflet-popup .leaflet-popup-content-wrapper {
|
|
1737
|
+
.custom-leaflet-popup .leaflet-popup-content-wrapper {
|
|
1550
1738
|
border-radius: 12px;
|
|
1551
|
-
box-shadow:
|
|
1552
|
-
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
1553
|
-
0 2px 4px -2px rgba(0, 0, 0, 0.1),
|
|
1554
|
-
0 0 0 1px rgba(0, 0, 0, 0.05);
|
|
1555
1739
|
padding: 0;
|
|
1556
1740
|
background: #ffffff;
|
|
1557
|
-
|
|
1741
|
+
box-shadow: 0 12px 24px rgba(15, 23, 42, 0.18);
|
|
1742
|
+
border: 1px solid rgba(15, 23, 42, 0.08);
|
|
1558
1743
|
}
|
|
1559
1744
|
|
|
1560
|
-
|
|
1561
|
-
.zenit-leaflet-popup .leaflet-popup-content {
|
|
1745
|
+
.custom-leaflet-popup .leaflet-popup-content {
|
|
1562
1746
|
margin: 0;
|
|
1563
|
-
padding:
|
|
1747
|
+
padding: 12px 14px;
|
|
1564
1748
|
font-size: 13px;
|
|
1565
|
-
line-height: 1.
|
|
1566
|
-
color: #
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
overflow-y: auto;
|
|
1570
|
-
overflow-x: hidden;
|
|
1749
|
+
line-height: 1.4;
|
|
1750
|
+
color: #0f172a;
|
|
1751
|
+
max-height: min(70vh, 520px);
|
|
1752
|
+
overflow: auto;
|
|
1571
1753
|
scrollbar-width: thin;
|
|
1572
|
-
scrollbar-color: rgba(
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
/* Popup tip/arrow shadow */
|
|
1576
|
-
.zenit-leaflet-popup .leaflet-popup-tip-container {
|
|
1577
|
-
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
|
|
1578
|
-
}
|
|
1579
|
-
|
|
1580
|
-
.zenit-leaflet-popup .leaflet-popup-tip {
|
|
1581
|
-
background: #ffffff;
|
|
1582
|
-
box-shadow: none;
|
|
1754
|
+
scrollbar-color: rgba(148, 163, 184, 0.6) transparent;
|
|
1583
1755
|
}
|
|
1584
1756
|
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
height: 28px;
|
|
1592
|
-
padding: 0;
|
|
1593
|
-
margin: 8px 8px 0 0;
|
|
1594
|
-
display: flex;
|
|
1595
|
-
align-items: center;
|
|
1596
|
-
justify-content: center;
|
|
1597
|
-
border-radius: 6px;
|
|
1598
|
-
transition: all 0.15s ease;
|
|
1599
|
-
z-index: 10;
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
.zenit-leaflet-popup .leaflet-popup-close-button:hover {
|
|
1603
|
-
color: #374151;
|
|
1604
|
-
background-color: #f3f4f6;
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
.zenit-leaflet-popup .leaflet-popup-close-button:active {
|
|
1608
|
-
background-color: #e5e7eb;
|
|
1609
|
-
}
|
|
1610
|
-
|
|
1611
|
-
/* Main card container */
|
|
1612
|
-
.zenit-popup-card {
|
|
1613
|
-
display: flex;
|
|
1614
|
-
flex-direction: column;
|
|
1615
|
-
gap: 0;
|
|
1616
|
-
padding: 16px;
|
|
1617
|
-
}
|
|
1618
|
-
|
|
1619
|
-
.zenit-popup-header {
|
|
1620
|
-
padding-bottom: 12px;
|
|
1621
|
-
border-bottom: 1px solid #e5e7eb;
|
|
1622
|
-
margin-bottom: 4px;
|
|
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;
|
|
1623
1763
|
}
|
|
1624
1764
|
|
|
1625
|
-
.
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
color: #111827;
|
|
1629
|
-
letter-spacing: 0.01em;
|
|
1630
|
-
line-height: 1.4;
|
|
1765
|
+
.custom-leaflet-popup .leaflet-popup-close-button:hover {
|
|
1766
|
+
color: #0f172a;
|
|
1767
|
+
background: rgba(148, 163, 184, 0.2);
|
|
1631
1768
|
}
|
|
1632
1769
|
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
display: flex;
|
|
1636
|
-
flex-direction: column;
|
|
1637
|
-
gap: 2px;
|
|
1638
|
-
padding: 10px 0;
|
|
1639
|
-
border-bottom: 1px solid #f3f4f6;
|
|
1770
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar {
|
|
1771
|
+
width: 6px;
|
|
1640
1772
|
}
|
|
1641
1773
|
|
|
1642
|
-
.
|
|
1643
|
-
|
|
1774
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb {
|
|
1775
|
+
background: rgba(148, 163, 184, 0.5);
|
|
1776
|
+
border-radius: 999px;
|
|
1644
1777
|
}
|
|
1645
1778
|
|
|
1646
|
-
.
|
|
1647
|
-
|
|
1648
|
-
padding-bottom: 0;
|
|
1779
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-track {
|
|
1780
|
+
background: transparent;
|
|
1649
1781
|
}
|
|
1650
1782
|
|
|
1651
|
-
|
|
1652
|
-
.
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
letter-spacing: 0.05em;
|
|
1658
|
-
line-height: 1.4;
|
|
1659
|
-
}
|
|
1783
|
+
@media (max-width: 640px) {
|
|
1784
|
+
.custom-leaflet-popup .leaflet-popup-content {
|
|
1785
|
+
font-size: 12px;
|
|
1786
|
+
padding: 10px 12px;
|
|
1787
|
+
max-height: min(65vh, 420px);
|
|
1788
|
+
}
|
|
1660
1789
|
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
color: #1f2937;
|
|
1666
|
-
overflow-wrap: break-word;
|
|
1667
|
-
word-break: break-word;
|
|
1668
|
-
line-height: 1.5;
|
|
1790
|
+
.custom-leaflet-popup .leaflet-popup-close-button {
|
|
1791
|
+
font-size: 14px;
|
|
1792
|
+
padding: 4px 6px;
|
|
1793
|
+
}
|
|
1669
1794
|
}
|
|
1670
1795
|
|
|
1671
|
-
.zenit-
|
|
1672
|
-
color:
|
|
1673
|
-
|
|
1796
|
+
.zenit-map-tooltip {
|
|
1797
|
+
background-color: rgba(31, 41, 55, 0.95);
|
|
1798
|
+
border: none;
|
|
1799
|
+
border-radius: 6px;
|
|
1800
|
+
color: #ffffff;
|
|
1801
|
+
font-size: 12px;
|
|
1674
1802
|
font-weight: 500;
|
|
1803
|
+
padding: 6px 10px;
|
|
1804
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
1675
1805
|
}
|
|
1676
1806
|
|
|
1677
|
-
.zenit-
|
|
1678
|
-
color:
|
|
1679
|
-
}
|
|
1680
|
-
|
|
1681
|
-
/* Special styling for description field */
|
|
1682
|
-
.zenit-popup-row.zenit-popup-description {
|
|
1683
|
-
background-color: #f9fafb;
|
|
1684
|
-
margin: 0 -16px;
|
|
1685
|
-
padding: 12px 16px;
|
|
1686
|
-
border-bottom: 1px solid #e5e7eb;
|
|
1687
|
-
}
|
|
1688
|
-
|
|
1689
|
-
.zenit-popup-row.zenit-popup-description:first-child {
|
|
1690
|
-
margin-top: 0;
|
|
1691
|
-
border-radius: 0;
|
|
1692
|
-
}
|
|
1693
|
-
|
|
1694
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value {
|
|
1695
|
-
font-size: 13px;
|
|
1696
|
-
line-height: 1.6;
|
|
1697
|
-
color: #374151;
|
|
1698
|
-
max-height: 150px;
|
|
1699
|
-
overflow-y: auto;
|
|
1700
|
-
padding-right: 4px;
|
|
1807
|
+
.zenit-map-tooltip::before {
|
|
1808
|
+
border-top-color: rgba(31, 41, 55, 0.95);
|
|
1701
1809
|
}
|
|
1702
1810
|
|
|
1703
|
-
|
|
1704
|
-
.
|
|
1705
|
-
|
|
1706
|
-
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
1707
|
-
font-size: 11px;
|
|
1708
|
-
white-space: pre-wrap;
|
|
1709
|
-
word-break: break-word;
|
|
1710
|
-
color: #4b5563;
|
|
1711
|
-
background-color: #f9fafb;
|
|
1712
|
-
padding: 8px;
|
|
1811
|
+
.polygon-label-tooltip {
|
|
1812
|
+
background: rgba(15, 23, 42, 0.92);
|
|
1813
|
+
border: none;
|
|
1713
1814
|
border-radius: 6px;
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
.zenit-popup-empty {
|
|
1719
|
-
font-size: 13px;
|
|
1720
|
-
color: #9ca3af;
|
|
1721
|
-
font-style: italic;
|
|
1722
|
-
text-align: center;
|
|
1723
|
-
padding: 20px 0;
|
|
1815
|
+
color: #f8fafc;
|
|
1816
|
+
font-weight: 600;
|
|
1817
|
+
font-size: 12px;
|
|
1818
|
+
padding: 4px 8px;
|
|
1724
1819
|
}
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
.
|
|
1728
|
-
width: 6px;
|
|
1820
|
+
`;
|
|
1821
|
+
function clampNumber2(value, min, max) {
|
|
1822
|
+
return Math.min(max, Math.max(min, value));
|
|
1729
1823
|
}
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
background: transparent;
|
|
1824
|
+
function clampOpacity4(value) {
|
|
1825
|
+
return clampNumber2(value, 0, 1);
|
|
1733
1826
|
}
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1827
|
+
function ensurePopupStyles() {
|
|
1828
|
+
if (typeof document === "undefined") return;
|
|
1829
|
+
if (document.getElementById(POPUP_STYLE_ID)) return;
|
|
1830
|
+
const styleTag = document.createElement("style");
|
|
1831
|
+
styleTag.id = POPUP_STYLE_ID;
|
|
1832
|
+
styleTag.textContent = ZENIT_LEAFLET_POPUP_STYLES;
|
|
1833
|
+
document.head.appendChild(styleTag);
|
|
1738
1834
|
}
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1835
|
+
function getPopupDimensions() {
|
|
1836
|
+
if (typeof window === "undefined") {
|
|
1837
|
+
return DESKTOP_POPUP_DIMENSIONS;
|
|
1838
|
+
}
|
|
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 };
|
|
1742
1844
|
}
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar {
|
|
1746
|
-
width: 4px;
|
|
1845
|
+
function escapeHtml(value) {
|
|
1846
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1747
1847
|
}
|
|
1748
|
-
|
|
1749
|
-
.
|
|
1750
|
-
background: transparent;
|
|
1848
|
+
function formatLabel(key) {
|
|
1849
|
+
return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").trim();
|
|
1751
1850
|
}
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
}
|
|
1757
|
-
|
|
1758
|
-
/* ===== Responsive: Mobile (<640px) ===== */
|
|
1759
|
-
@media (max-width: 640px) {
|
|
1760
|
-
.zenit-leaflet-popup .leaflet-popup-content-wrapper {
|
|
1761
|
-
border-radius: 10px;
|
|
1851
|
+
function renderPopupValue(value) {
|
|
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"));
|
|
1762
1855
|
}
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
width: 26px;
|
|
1766
|
-
height: 26px;
|
|
1767
|
-
font-size: 16px;
|
|
1768
|
-
margin: 6px 6px 0 0;
|
|
1856
|
+
if (typeof value === "number") {
|
|
1857
|
+
return escapeHtml(value.toLocaleString("es-GT"));
|
|
1769
1858
|
}
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
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);
|
|
1773
1863
|
}
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1864
|
+
if (typeof value === "object") {
|
|
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
|
+
}
|
|
1777
1872
|
}
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
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;
|
|
1882
|
+
}
|
|
1883
|
+
function shouldIncludePopupEntry(key, value) {
|
|
1884
|
+
if (!key) return false;
|
|
1885
|
+
const normalized = key.trim().toLowerCase();
|
|
1886
|
+
if (!normalized) return false;
|
|
1887
|
+
if (normalized.startsWith("_")) return false;
|
|
1888
|
+
if (POPUP_EXCLUDED_KEYS.has(normalized)) return false;
|
|
1889
|
+
if (value === null || value === void 0) return false;
|
|
1890
|
+
if (typeof value === "string" && !value.trim()) return false;
|
|
1891
|
+
return true;
|
|
1892
|
+
}
|
|
1893
|
+
function createPopupContent(properties) {
|
|
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
|
+
});
|
|
1900
|
+
if (entries.length === 0) {
|
|
1901
|
+
return '<div style="padding:8px 0; color:#64748b; text-align:center;">Sin datos disponibles</div>';
|
|
1781
1902
|
}
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
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]) => {
|
|
1907
|
+
const label = escapeHtml(formatLabel(key));
|
|
1908
|
+
const valueHtml = renderPopupValue(value);
|
|
1909
|
+
return `
|
|
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>
|
|
1913
|
+
</div>
|
|
1914
|
+
`;
|
|
1915
|
+
}).join("");
|
|
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
|
+
}
|
|
1785
1956
|
}
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
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
|
+
}
|
|
1789
1963
|
}
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
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)" };
|
|
1793
1970
|
}
|
|
1794
|
-
|
|
1795
|
-
.
|
|
1796
|
-
|
|
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)" };
|
|
1797
1974
|
}
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
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
|
+
}
|
|
1802
1988
|
}
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
max-height: 120px;
|
|
1989
|
+
if (trimmed.startsWith("rgb(")) {
|
|
1990
|
+
const inner = trimmed.slice(4, -1);
|
|
1991
|
+
return `rgba(${inner}, ${alpha})`;
|
|
1807
1992
|
}
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
padding: 6px;
|
|
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})`;
|
|
1812
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
|
+
}
|
|
1813
2064
|
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
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;
|
|
1818
2073
|
}
|
|
1819
2074
|
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
2075
|
+
.zenit-location-button {
|
|
2076
|
+
width: 42px;
|
|
2077
|
+
height: 42px;
|
|
2078
|
+
border-radius: 12px;
|
|
1823
2079
|
border: none;
|
|
1824
|
-
|
|
1825
|
-
color: #
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
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;
|
|
1830
2088
|
}
|
|
1831
2089
|
|
|
1832
|
-
.zenit-
|
|
1833
|
-
|
|
2090
|
+
.zenit-location-button.zenit-location-button--tracking {
|
|
2091
|
+
animation: zenitLocationPulse 1.8s infinite;
|
|
1834
2092
|
}
|
|
1835
2093
|
|
|
1836
|
-
.
|
|
1837
|
-
|
|
2094
|
+
.zenit-location-button:hover {
|
|
2095
|
+
background: #f8fafc;
|
|
1838
2096
|
}
|
|
1839
2097
|
|
|
1840
|
-
.zenit-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
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);
|
|
1845
2113
|
}
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
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);
|
|
1854
2123
|
}
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
}
|
|
1859
|
-
|
|
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); }
|
|
1860
2129
|
}
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
}
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
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;
|
|
1871
2238
|
}
|
|
1872
|
-
function
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
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 }
|
|
1876
2251
|
);
|
|
1877
|
-
if (!matches) return null;
|
|
1878
|
-
return normalizeDescriptionValue(matches[1]);
|
|
1879
2252
|
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
if (
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
}
|
|
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);
|
|
1906
2278
|
}
|
|
1907
|
-
|
|
1908
|
-
const
|
|
1909
|
-
|
|
1910
|
-
const safeHref = escapeHtml(parsedUrl.toString());
|
|
1911
|
-
return `<a class="zenit-popup-link" href="${safeHref}" target="_blank" rel="noopener noreferrer">${safeHref}</a>`;
|
|
1912
|
-
}
|
|
1913
|
-
} catch {
|
|
2279
|
+
if (!resolvedBBox && autoGeojson.length > 0) {
|
|
2280
|
+
const bboxes = autoGeojson.map((collection) => computeBBoxFromGeojson(collection));
|
|
2281
|
+
resolvedBBox = mergeBBoxes(bboxes);
|
|
1914
2282
|
}
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
return `<span>${escapeHtml(String(value))}</span>`;
|
|
1922
|
-
}
|
|
1923
|
-
function shouldIncludePopupEntry(key, value) {
|
|
1924
|
-
if (!key) return false;
|
|
1925
|
-
const normalized = key.trim().toLowerCase();
|
|
1926
|
-
if (!normalized) return false;
|
|
1927
|
-
if (normalized.startsWith("_")) return false;
|
|
1928
|
-
if (POPUP_EXCLUDED_KEYS.has(normalized)) return false;
|
|
1929
|
-
if (value === null || value === void 0) return false;
|
|
1930
|
-
if (typeof value === "string" && !value.trim()) return false;
|
|
1931
|
-
return true;
|
|
1932
|
-
}
|
|
1933
|
-
function isDescriptionKey(key) {
|
|
1934
|
-
const normalized = key.trim().toLowerCase();
|
|
1935
|
-
return DESCRIPTION_KEYS.has(normalized);
|
|
1936
|
-
}
|
|
1937
|
-
function extractPopupHeader(properties) {
|
|
1938
|
-
if (!properties) return null;
|
|
1939
|
-
const entry = Object.entries(properties).find(
|
|
1940
|
-
(candidate) => {
|
|
1941
|
-
const [key, value] = candidate;
|
|
1942
|
-
return POPUP_HEADER_KEYS.includes(key.trim().toLowerCase()) && typeof value === "string" && value.trim().length > 0;
|
|
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;
|
|
1943
2289
|
}
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
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;
|
|
1947
2328
|
}
|
|
1948
|
-
function
|
|
1949
|
-
|
|
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";
|
|
1950
2335
|
}
|
|
1951
|
-
function
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
if (headerText && POPUP_HEADER_KEYS.includes(key.trim().toLowerCase())) {
|
|
1956
|
-
return false;
|
|
1957
|
-
}
|
|
1958
|
-
return true;
|
|
1959
|
-
});
|
|
1960
|
-
if (entries.length === 0) {
|
|
1961
|
-
return `<div class="zenit-popup-card"><div class="zenit-popup-empty">Sin datos disponibles</div></div>`;
|
|
1962
|
-
}
|
|
1963
|
-
const descriptionEntry = entries.find(([key]) => isDescriptionKey(key));
|
|
1964
|
-
const otherEntries = entries.filter(([key]) => !isDescriptionKey(key));
|
|
1965
|
-
let rowsHtml = "";
|
|
1966
|
-
if (descriptionEntry) {
|
|
1967
|
-
const [key, value] = descriptionEntry;
|
|
1968
|
-
const label = escapeHtml(formatLabel(key));
|
|
1969
|
-
const valueHtml = renderPopupValue(value);
|
|
1970
|
-
rowsHtml += `
|
|
1971
|
-
<div class="zenit-popup-row zenit-popup-description">
|
|
1972
|
-
<div class="zenit-popup-label">${label}</div>
|
|
1973
|
-
<div class="zenit-popup-value">${valueHtml}</div>
|
|
1974
|
-
</div>
|
|
1975
|
-
`;
|
|
2336
|
+
function extractGeoJsonFeatureCollection(value) {
|
|
2337
|
+
if (isRecord(value) && "data" in value) {
|
|
2338
|
+
const data = value.data;
|
|
2339
|
+
return isGeoJsonFeatureCollection(data) ? data : null;
|
|
1976
2340
|
}
|
|
1977
|
-
|
|
1978
|
-
const label = escapeHtml(formatLabel(key));
|
|
1979
|
-
const valueHtml = renderPopupValue(value);
|
|
1980
|
-
return `
|
|
1981
|
-
<div class="zenit-popup-row">
|
|
1982
|
-
<div class="zenit-popup-label">${label}</div>
|
|
1983
|
-
<div class="zenit-popup-value">${valueHtml}</div>
|
|
1984
|
-
</div>
|
|
1985
|
-
`;
|
|
1986
|
-
}).join("");
|
|
1987
|
-
const headerHtml = headerText ? `<div class="zenit-popup-header"><div class="zenit-popup-title">${escapeHtml(
|
|
1988
|
-
headerText
|
|
1989
|
-
)}</div></div>` : "";
|
|
1990
|
-
return `<div class="zenit-popup-card">${headerHtml}${rowsHtml}</div>`;
|
|
2341
|
+
return isGeoJsonFeatureCollection(value) ? value : null;
|
|
1991
2342
|
}
|
|
1992
|
-
function
|
|
1993
|
-
const
|
|
1994
|
-
if (
|
|
1995
|
-
|
|
1996
|
-
const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
|
|
1997
|
-
if (expanded.length === 6) {
|
|
1998
|
-
const r = parseInt(expanded.slice(0, 2), 16);
|
|
1999
|
-
const g = parseInt(expanded.slice(2, 4), 16);
|
|
2000
|
-
const b = parseInt(expanded.slice(4, 6), 16);
|
|
2001
|
-
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
2002
|
-
}
|
|
2003
|
-
}
|
|
2004
|
-
if (trimmed.startsWith("rgb(")) {
|
|
2005
|
-
const inner = trimmed.slice(4, -1);
|
|
2006
|
-
return `rgba(${inner}, ${alpha})`;
|
|
2007
|
-
}
|
|
2008
|
-
if (trimmed.startsWith("rgba(")) {
|
|
2009
|
-
const inner = trimmed.slice(5, -1).split(",").slice(0, 3).map((value) => value.trim());
|
|
2010
|
-
return `rgba(${inner.join(", ")}, ${alpha})`;
|
|
2011
|
-
}
|
|
2012
|
-
return color;
|
|
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;
|
|
2013
2347
|
}
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
if (
|
|
2017
|
-
|
|
2018
|
-
const
|
|
2019
|
-
|
|
2020
|
-
const r = parseInt(expanded.slice(0, 2), 16);
|
|
2021
|
-
const g = parseInt(expanded.slice(2, 4), 16);
|
|
2022
|
-
const b = parseInt(expanded.slice(4, 6), 16);
|
|
2023
|
-
return { r, g, b };
|
|
2024
|
-
}
|
|
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;
|
|
2025
2354
|
}
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
const [r, g, b] = rgbMatch[1].split(",").map((value) => parseFloat(value.trim())).slice(0, 3);
|
|
2029
|
-
if ([r, g, b].every((value) => Number.isFinite(value))) {
|
|
2030
|
-
return { r, g, b };
|
|
2031
|
-
}
|
|
2355
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
2356
|
+
return String(value);
|
|
2032
2357
|
}
|
|
2033
2358
|
return null;
|
|
2034
2359
|
}
|
|
2035
|
-
function
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.7)" };
|
|
2043
|
-
}
|
|
2044
|
-
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]);
|
|
2045
2367
|
}
|
|
2046
2368
|
function getFeatureStyleOverrides(feature) {
|
|
2047
2369
|
const candidate = feature?.properties?._style;
|
|
@@ -2060,25 +2382,6 @@ function buildFeaturePopupHtml(feature) {
|
|
|
2060
2382
|
const rendered = createPopupContent(properties);
|
|
2061
2383
|
return rendered ? rendered : null;
|
|
2062
2384
|
}
|
|
2063
|
-
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
2064
|
-
function getGeometryType(feature) {
|
|
2065
|
-
const t = feature?.geometry?.type;
|
|
2066
|
-
return typeof t === "string" ? t : null;
|
|
2067
|
-
}
|
|
2068
|
-
function isPointGeometry(feature) {
|
|
2069
|
-
const geometryType = getGeometryType(feature);
|
|
2070
|
-
return geometryType !== null && POINT_GEOMETRY_TYPES.has(geometryType);
|
|
2071
|
-
}
|
|
2072
|
-
function isNonPointGeometry(feature) {
|
|
2073
|
-
const geometryType = getGeometryType(feature);
|
|
2074
|
-
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
2075
|
-
}
|
|
2076
|
-
function buildFeatureCollection(features) {
|
|
2077
|
-
return {
|
|
2078
|
-
type: "FeatureCollection",
|
|
2079
|
-
features
|
|
2080
|
-
};
|
|
2081
|
-
}
|
|
2082
2385
|
function pickIntersectFeature(baseFeature, candidates) {
|
|
2083
2386
|
if (!Array.isArray(candidates) || candidates.length === 0) return null;
|
|
2084
2387
|
const baseId = baseFeature?.id;
|
|
@@ -2105,81 +2408,7 @@ function normalizeCenterTuple(center) {
|
|
|
2105
2408
|
}
|
|
2106
2409
|
return null;
|
|
2107
2410
|
}
|
|
2108
|
-
var
|
|
2109
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
2110
|
-
const lastAppliedBBox = (0, import_react.useRef)(null);
|
|
2111
|
-
(0, import_react.useEffect)(() => {
|
|
2112
|
-
const targetBBox = bbox;
|
|
2113
|
-
if (!targetBBox) return;
|
|
2114
|
-
const serialized = JSON.stringify(targetBBox);
|
|
2115
|
-
if (lastAppliedBBox.current === serialized) return;
|
|
2116
|
-
const bounds = [
|
|
2117
|
-
[targetBBox.minLat, targetBBox.minLon],
|
|
2118
|
-
[targetBBox.maxLat, targetBBox.maxLon]
|
|
2119
|
-
];
|
|
2120
|
-
mapInstance.fitBounds(bounds, { padding: [12, 12] });
|
|
2121
|
-
lastAppliedBBox.current = serialized;
|
|
2122
|
-
}, [bbox, mapInstance]);
|
|
2123
|
-
return null;
|
|
2124
|
-
};
|
|
2125
|
-
var AutoFitToBounds = ({
|
|
2126
|
-
bbox,
|
|
2127
|
-
enabled = true
|
|
2128
|
-
}) => {
|
|
2129
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
2130
|
-
const lastAutoBBoxApplied = (0, import_react.useRef)(null);
|
|
2131
|
-
const lastUserInteracted = (0, import_react.useRef)(false);
|
|
2132
|
-
(0, import_react.useEffect)(() => {
|
|
2133
|
-
if (!enabled) return;
|
|
2134
|
-
const handleInteraction = () => {
|
|
2135
|
-
lastUserInteracted.current = true;
|
|
2136
|
-
};
|
|
2137
|
-
mapInstance.on("dragstart", handleInteraction);
|
|
2138
|
-
mapInstance.on("zoomstart", handleInteraction);
|
|
2139
|
-
return () => {
|
|
2140
|
-
mapInstance.off("dragstart", handleInteraction);
|
|
2141
|
-
mapInstance.off("zoomstart", handleInteraction);
|
|
2142
|
-
};
|
|
2143
|
-
}, [enabled, mapInstance]);
|
|
2144
|
-
(0, import_react.useEffect)(() => {
|
|
2145
|
-
if (!enabled) return;
|
|
2146
|
-
if (!bbox) return;
|
|
2147
|
-
const serialized = JSON.stringify(bbox);
|
|
2148
|
-
if (lastAutoBBoxApplied.current === serialized) return;
|
|
2149
|
-
if (lastUserInteracted.current) {
|
|
2150
|
-
lastUserInteracted.current = false;
|
|
2151
|
-
}
|
|
2152
|
-
const bounds = [
|
|
2153
|
-
[bbox.minLat, bbox.minLon],
|
|
2154
|
-
[bbox.maxLat, bbox.maxLon]
|
|
2155
|
-
];
|
|
2156
|
-
mapInstance.fitBounds(bounds, { padding: [12, 12] });
|
|
2157
|
-
lastAutoBBoxApplied.current = serialized;
|
|
2158
|
-
}, [bbox, enabled, mapInstance]);
|
|
2159
|
-
return null;
|
|
2160
|
-
};
|
|
2161
|
-
var ZoomBasedOpacityHandler = ({ onZoomChange }) => {
|
|
2162
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
2163
|
-
(0, import_react.useEffect)(() => {
|
|
2164
|
-
const handleZoom = () => {
|
|
2165
|
-
onZoomChange(mapInstance.getZoom());
|
|
2166
|
-
};
|
|
2167
|
-
mapInstance.on("zoomend", handleZoom);
|
|
2168
|
-
handleZoom();
|
|
2169
|
-
return () => {
|
|
2170
|
-
mapInstance.off("zoomend", handleZoom);
|
|
2171
|
-
};
|
|
2172
|
-
}, [mapInstance, onZoomChange]);
|
|
2173
|
-
return null;
|
|
2174
|
-
};
|
|
2175
|
-
var MapInstanceBridge = ({ onReady }) => {
|
|
2176
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
2177
|
-
(0, import_react.useEffect)(() => {
|
|
2178
|
-
onReady(mapInstance);
|
|
2179
|
-
}, [mapInstance, onReady]);
|
|
2180
|
-
return null;
|
|
2181
|
-
};
|
|
2182
|
-
var ZenitMap = (0, import_react.forwardRef)(({
|
|
2411
|
+
var ZenitMap = (0, import_react4.forwardRef)(({
|
|
2183
2412
|
client,
|
|
2184
2413
|
mapId,
|
|
2185
2414
|
height = "500px",
|
|
@@ -2204,21 +2433,21 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2204
2433
|
onZoomChange,
|
|
2205
2434
|
onMapReady
|
|
2206
2435
|
}, ref) => {
|
|
2207
|
-
const [map, setMap] = (0,
|
|
2208
|
-
const [layers, setLayers] = (0,
|
|
2209
|
-
const [effectiveStates, setEffectiveStates] = (0,
|
|
2210
|
-
const [loadingMap, setLoadingMap] = (0,
|
|
2211
|
-
const [mapError, setMapError] = (0,
|
|
2212
|
-
const [mapInstance, setMapInstance] = (0,
|
|
2213
|
-
const [panesReady, setPanesReady] = (0,
|
|
2214
|
-
const [currentZoom, setCurrentZoom] = (0,
|
|
2215
|
-
const [isPopupOpen, setIsPopupOpen] = (0,
|
|
2216
|
-
const [isMobile, setIsMobile] = (0,
|
|
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)(() => {
|
|
2217
2446
|
if (typeof window === "undefined") return false;
|
|
2218
2447
|
return window.matchMedia("(max-width: 768px)").matches;
|
|
2219
2448
|
});
|
|
2220
|
-
const normalizedLayers = (0,
|
|
2221
|
-
(0,
|
|
2449
|
+
const normalizedLayers = (0, import_react4.useMemo)(() => normalizeMapLayers(map), [map]);
|
|
2450
|
+
(0, import_react4.useEffect)(() => {
|
|
2222
2451
|
if (typeof window === "undefined") return;
|
|
2223
2452
|
const mql = window.matchMedia("(max-width: 768px)");
|
|
2224
2453
|
const onChange = (e) => {
|
|
@@ -2236,17 +2465,17 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2236
2465
|
}
|
|
2237
2466
|
return;
|
|
2238
2467
|
}, []);
|
|
2239
|
-
(0,
|
|
2468
|
+
(0, import_react4.useEffect)(() => {
|
|
2240
2469
|
if (featureInfoMode === "popup") {
|
|
2241
2470
|
ensurePopupStyles();
|
|
2242
2471
|
}
|
|
2243
2472
|
}, [featureInfoMode]);
|
|
2244
|
-
(0,
|
|
2473
|
+
(0, import_react4.useEffect)(() => {
|
|
2245
2474
|
if (featureInfoMode !== "popup") {
|
|
2246
2475
|
setIsPopupOpen(false);
|
|
2247
2476
|
}
|
|
2248
2477
|
}, [featureInfoMode]);
|
|
2249
|
-
(0,
|
|
2478
|
+
(0, import_react4.useEffect)(() => {
|
|
2250
2479
|
if (!mapInstance) return;
|
|
2251
2480
|
const popupPane = mapInstance.getPane("popupPane");
|
|
2252
2481
|
if (popupPane) {
|
|
@@ -2255,7 +2484,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2255
2484
|
const labelsPane = mapInstance.getPane(LABELS_PANE_NAME) ?? mapInstance.createPane(LABELS_PANE_NAME);
|
|
2256
2485
|
labelsPane.style.zIndex = "600";
|
|
2257
2486
|
}, [mapInstance]);
|
|
2258
|
-
(0,
|
|
2487
|
+
(0, import_react4.useEffect)(() => {
|
|
2259
2488
|
if (!mapInstance) return;
|
|
2260
2489
|
const handlePopupOpen = () => setIsPopupOpen(true);
|
|
2261
2490
|
const handlePopupClose = () => setIsPopupOpen(false);
|
|
@@ -2266,7 +2495,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2266
2495
|
mapInstance.off("popupclose", handlePopupClose);
|
|
2267
2496
|
};
|
|
2268
2497
|
}, [mapInstance]);
|
|
2269
|
-
const layerStyleIndex = (0,
|
|
2498
|
+
const layerStyleIndex = (0, import_react4.useMemo)(() => {
|
|
2270
2499
|
const index = /* @__PURE__ */ new Map();
|
|
2271
2500
|
(map?.mapLayers ?? []).forEach((entry) => {
|
|
2272
2501
|
const layerStyle = entry.layer?.style ?? entry.mapLayer?.layer?.style ?? entry.style ?? null;
|
|
@@ -2277,7 +2506,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2277
2506
|
});
|
|
2278
2507
|
return index;
|
|
2279
2508
|
}, [map]);
|
|
2280
|
-
const labelKeyIndex = (0,
|
|
2509
|
+
const labelKeyIndex = (0, import_react4.useMemo)(() => {
|
|
2281
2510
|
const index = /* @__PURE__ */ new Map();
|
|
2282
2511
|
normalizedLayers.forEach((entry) => {
|
|
2283
2512
|
const label = entry.layer?.label ?? entry.mapLayer?.label ?? entry.mapLayer.layerConfig?.label;
|
|
@@ -2287,7 +2516,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2287
2516
|
});
|
|
2288
2517
|
return index;
|
|
2289
2518
|
}, [normalizedLayers]);
|
|
2290
|
-
const layerMetaIndex = (0,
|
|
2519
|
+
const layerMetaIndex = (0, import_react4.useMemo)(() => {
|
|
2291
2520
|
const index = /* @__PURE__ */ new Map();
|
|
2292
2521
|
normalizedLayers.forEach((entry) => {
|
|
2293
2522
|
index.set(String(entry.layerId), {
|
|
@@ -2297,7 +2526,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2297
2526
|
});
|
|
2298
2527
|
return index;
|
|
2299
2528
|
}, [normalizedLayers]);
|
|
2300
|
-
const overlayStyleFunction = (0,
|
|
2529
|
+
const overlayStyleFunction = (0, import_react4.useMemo)(() => {
|
|
2301
2530
|
return (feature) => {
|
|
2302
2531
|
const featureLayerId = getFeatureLayerId(feature);
|
|
2303
2532
|
const featureStyleOverrides = getFeatureStyleOverrides(feature);
|
|
@@ -2316,11 +2545,15 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2316
2545
|
return defaultOptions;
|
|
2317
2546
|
};
|
|
2318
2547
|
}, [layerStyleIndex, mapLayers, overlayStyle]);
|
|
2319
|
-
const
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
(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)(() => {
|
|
2324
2557
|
let isMounted = true;
|
|
2325
2558
|
setLoadingMap(true);
|
|
2326
2559
|
setMapError(null);
|
|
@@ -2343,7 +2576,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2343
2576
|
isMounted = false;
|
|
2344
2577
|
};
|
|
2345
2578
|
}, [client.maps, mapId, onError, onLoadingChange]);
|
|
2346
|
-
(0,
|
|
2579
|
+
(0, import_react4.useEffect)(() => {
|
|
2347
2580
|
if (normalizedLayers.length === 0) {
|
|
2348
2581
|
setLayers([]);
|
|
2349
2582
|
setBaseStates([]);
|
|
@@ -2374,7 +2607,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2374
2607
|
setMapOverrides(initialOverrides);
|
|
2375
2608
|
setUiOverrides([]);
|
|
2376
2609
|
}, [normalizedLayers]);
|
|
2377
|
-
(0,
|
|
2610
|
+
(0, import_react4.useEffect)(() => {
|
|
2378
2611
|
if (!layerControls) {
|
|
2379
2612
|
setControlOverrides([]);
|
|
2380
2613
|
return;
|
|
@@ -2386,7 +2619,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2386
2619
|
}));
|
|
2387
2620
|
setControlOverrides(overrides);
|
|
2388
2621
|
}, [layerControls]);
|
|
2389
|
-
(0,
|
|
2622
|
+
(0, import_react4.useEffect)(() => {
|
|
2390
2623
|
if (layerStates) {
|
|
2391
2624
|
return;
|
|
2392
2625
|
}
|
|
@@ -2396,12 +2629,12 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2396
2629
|
onLayerStateChange?.(reset);
|
|
2397
2630
|
}
|
|
2398
2631
|
}, [baseStates, effectiveStates.length, layerControls, layerStates, onLayerStateChange]);
|
|
2399
|
-
(0,
|
|
2632
|
+
(0, import_react4.useEffect)(() => {
|
|
2400
2633
|
if (layerStates) {
|
|
2401
2634
|
setEffectiveStates(layerStates);
|
|
2402
2635
|
}
|
|
2403
2636
|
}, [layerStates]);
|
|
2404
|
-
(0,
|
|
2637
|
+
(0, import_react4.useEffect)(() => {
|
|
2405
2638
|
if (layerStates) {
|
|
2406
2639
|
return;
|
|
2407
2640
|
}
|
|
@@ -2414,11 +2647,11 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2414
2647
|
setEffectiveStates(next);
|
|
2415
2648
|
onLayerStateChange?.(next);
|
|
2416
2649
|
}, [baseStates, controlOverrides, layerStates, mapOverrides, onLayerStateChange, uiOverrides]);
|
|
2417
|
-
(0,
|
|
2650
|
+
(0, import_react4.useEffect)(() => {
|
|
2418
2651
|
if (!Array.isArray(layerControls) || layerControls.length > 0) return;
|
|
2419
2652
|
setUiOverrides([]);
|
|
2420
2653
|
}, [layerControls]);
|
|
2421
|
-
(0,
|
|
2654
|
+
(0, import_react4.useEffect)(() => {
|
|
2422
2655
|
if (layerStates) {
|
|
2423
2656
|
return;
|
|
2424
2657
|
}
|
|
@@ -2438,18 +2671,13 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2438
2671
|
return [...filtered, nextEntry];
|
|
2439
2672
|
});
|
|
2440
2673
|
};
|
|
2441
|
-
const updateOpacityFromUi = (0,
|
|
2674
|
+
const updateOpacityFromUi = (0, import_react4.useCallback)(
|
|
2442
2675
|
(layerId, uiOpacity) => {
|
|
2443
2676
|
const meta = layerMetaIndex.get(String(layerId));
|
|
2444
|
-
const
|
|
2677
|
+
const baseOpacity = clampOpacity3(uiOpacity);
|
|
2678
|
+
const effectiveOpacity = calculateZoomBasedOpacity(
|
|
2445
2679
|
currentZoom,
|
|
2446
|
-
meta?.layerType,
|
|
2447
|
-
meta?.geometryType
|
|
2448
|
-
);
|
|
2449
|
-
const baseOpacity = clampOpacity3(uiOpacity / zoomFactor);
|
|
2450
|
-
const effectiveOpacity = getEffectiveLayerOpacity(
|
|
2451
2680
|
baseOpacity,
|
|
2452
|
-
currentZoom,
|
|
2453
2681
|
meta?.layerType,
|
|
2454
2682
|
meta?.geometryType
|
|
2455
2683
|
);
|
|
@@ -2482,7 +2710,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2482
2710
|
},
|
|
2483
2711
|
[currentZoom, effectiveStates, layerMetaIndex, layerStates, onLayerStateChange]
|
|
2484
2712
|
);
|
|
2485
|
-
const center = (0,
|
|
2713
|
+
const center = (0, import_react4.useMemo)(() => {
|
|
2486
2714
|
if (initialCenter) {
|
|
2487
2715
|
return initialCenter;
|
|
2488
2716
|
}
|
|
@@ -2493,36 +2721,30 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2493
2721
|
return DEFAULT_CENTER;
|
|
2494
2722
|
}, [initialCenter, map?.settings?.center]);
|
|
2495
2723
|
const zoom = initialZoom ?? map?.settings?.zoom ?? DEFAULT_ZOOM;
|
|
2496
|
-
(0,
|
|
2724
|
+
(0, import_react4.useEffect)(() => {
|
|
2497
2725
|
setCurrentZoom(zoom);
|
|
2498
2726
|
}, [zoom]);
|
|
2499
|
-
const decoratedLayers = (0,
|
|
2727
|
+
const decoratedLayers = (0, import_react4.useMemo)(() => {
|
|
2500
2728
|
return layers.map((layer) => ({
|
|
2501
2729
|
...layer,
|
|
2502
2730
|
effective: effectiveStates.find((state) => state.layerId === layer.mapLayer.layerId),
|
|
2503
2731
|
data: layerGeojson?.[layer.mapLayer.layerId] ?? layerGeojson?.[String(layer.mapLayer.layerId)] ?? null
|
|
2504
2732
|
}));
|
|
2505
2733
|
}, [effectiveStates, layerGeojson, layers]);
|
|
2506
|
-
const orderedLayers = (0,
|
|
2734
|
+
const orderedLayers = (0, import_react4.useMemo)(() => {
|
|
2507
2735
|
return [...decoratedLayers].filter((layer) => layer.effective?.visible && layer.data).sort((a, b) => a.displayOrder - b.displayOrder);
|
|
2508
2736
|
}, [decoratedLayers]);
|
|
2509
|
-
const
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
const autoZoomBBox = (0, import_react.useMemo)(() => {
|
|
2515
|
-
if (explicitZoomBBox) return null;
|
|
2516
|
-
const visibleBBoxes = orderedLayers.map((layer) => computeBBoxFromGeojson(layer.data));
|
|
2517
|
-
return mergeBBoxes(visibleBBoxes);
|
|
2518
|
-
}, [explicitZoomBBox, orderedLayers]);
|
|
2519
|
-
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)(
|
|
2520
2742
|
(layerId) => {
|
|
2521
2743
|
return getStyleByLayerId(layerId, mapLayers) ?? layerStyleIndex.get(String(layerId)) ?? null;
|
|
2522
2744
|
},
|
|
2523
2745
|
[layerStyleIndex, mapLayers]
|
|
2524
2746
|
);
|
|
2525
|
-
const labelMarkers = (0,
|
|
2747
|
+
const labelMarkers = (0, import_react4.useMemo)(() => {
|
|
2526
2748
|
const markers = [];
|
|
2527
2749
|
decoratedLayers.forEach((layerState) => {
|
|
2528
2750
|
if (!layerState.effective?.visible) return;
|
|
@@ -2532,7 +2754,14 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2532
2754
|
if (!data) return;
|
|
2533
2755
|
const resolvedStyle = resolveLayerStyle(layerState.mapLayer.layerId);
|
|
2534
2756
|
const layerColor = resolvedStyle?.fillColor ?? resolvedStyle?.color ?? "rgba(37, 99, 235, 1)";
|
|
2535
|
-
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
|
+
);
|
|
2536
2765
|
data.features.forEach((feature, index) => {
|
|
2537
2766
|
const properties = feature.properties;
|
|
2538
2767
|
const value = properties?.[labelKey];
|
|
@@ -2551,8 +2780,8 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2551
2780
|
});
|
|
2552
2781
|
});
|
|
2553
2782
|
return markers;
|
|
2554
|
-
}, [decoratedLayers, labelKeyIndex, resolveLayerStyle]);
|
|
2555
|
-
const ensureLayerPanes = (0,
|
|
2783
|
+
}, [currentZoom, decoratedLayers, labelKeyIndex, layerMetaIndex, resolveLayerStyle]);
|
|
2784
|
+
const ensureLayerPanes = (0, import_react4.useCallback)(
|
|
2556
2785
|
(targetMap, targetLayers) => {
|
|
2557
2786
|
const baseZIndex = 400;
|
|
2558
2787
|
targetLayers.forEach((layer) => {
|
|
@@ -2568,7 +2797,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2568
2797
|
},
|
|
2569
2798
|
[]
|
|
2570
2799
|
);
|
|
2571
|
-
const handleMapReady = (0,
|
|
2800
|
+
const handleMapReady = (0, import_react4.useCallback)(
|
|
2572
2801
|
(instance) => {
|
|
2573
2802
|
setPanesReady(false);
|
|
2574
2803
|
setMapInstance(instance);
|
|
@@ -2576,7 +2805,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2576
2805
|
},
|
|
2577
2806
|
[onMapReady]
|
|
2578
2807
|
);
|
|
2579
|
-
(0,
|
|
2808
|
+
(0, import_react4.useEffect)(() => {
|
|
2580
2809
|
if (!mapInstance) {
|
|
2581
2810
|
setPanesReady(false);
|
|
2582
2811
|
return;
|
|
@@ -2596,19 +2825,19 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2596
2825
|
setPanesReady(true);
|
|
2597
2826
|
}
|
|
2598
2827
|
}, [mapInstance, orderedLayers, ensureLayerPanes]);
|
|
2599
|
-
const overlayOnEachFeature = (0,
|
|
2828
|
+
const overlayOnEachFeature = (0, import_react4.useMemo)(() => {
|
|
2600
2829
|
return (feature, layer) => {
|
|
2601
2830
|
const layerId = getFeatureLayerId(feature) ?? void 0;
|
|
2602
2831
|
const geometryType = feature?.geometry?.type;
|
|
2603
|
-
const isPointFeature = geometryType === "Point" || geometryType === "MultiPoint" || layer instanceof
|
|
2604
|
-
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 ? {
|
|
2605
2834
|
color: layer.options.color,
|
|
2606
2835
|
weight: layer.options.weight,
|
|
2607
2836
|
fillColor: layer.options.fillColor,
|
|
2608
2837
|
opacity: layer.options.opacity,
|
|
2609
2838
|
fillOpacity: layer.options.fillOpacity
|
|
2610
2839
|
} : null;
|
|
2611
|
-
const originalRadius = layer instanceof
|
|
2840
|
+
const originalRadius = layer instanceof import_leaflet4.default.CircleMarker ? layer.getRadius() : null;
|
|
2612
2841
|
if (featureInfoMode === "popup") {
|
|
2613
2842
|
const content = buildFeaturePopupHtml(feature);
|
|
2614
2843
|
if (content) {
|
|
@@ -2617,11 +2846,10 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2617
2846
|
maxWidth,
|
|
2618
2847
|
minWidth,
|
|
2619
2848
|
maxHeight,
|
|
2620
|
-
className: "
|
|
2849
|
+
className: "custom-leaflet-popup",
|
|
2621
2850
|
autoPan: true,
|
|
2622
2851
|
closeButton: true,
|
|
2623
|
-
keepInView: true
|
|
2624
|
-
offset: import_leaflet.default.point(0, -24)
|
|
2852
|
+
keepInView: true
|
|
2625
2853
|
});
|
|
2626
2854
|
}
|
|
2627
2855
|
}
|
|
@@ -2666,7 +2894,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2666
2894
|
onFeatureClick?.(feature, layerId);
|
|
2667
2895
|
});
|
|
2668
2896
|
layer.on("mouseover", () => {
|
|
2669
|
-
if (layer instanceof
|
|
2897
|
+
if (layer instanceof import_leaflet4.default.Path && originalStyle) {
|
|
2670
2898
|
layer.setStyle({
|
|
2671
2899
|
...originalStyle,
|
|
2672
2900
|
weight: (originalStyle.weight ?? 2) + 1,
|
|
@@ -2674,16 +2902,16 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2674
2902
|
fillOpacity: Math.min(1, (originalStyle.fillOpacity ?? 0.8) + 0.1)
|
|
2675
2903
|
});
|
|
2676
2904
|
}
|
|
2677
|
-
if (layer instanceof
|
|
2905
|
+
if (layer instanceof import_leaflet4.default.CircleMarker && typeof originalRadius === "number") {
|
|
2678
2906
|
layer.setRadius(originalRadius + 1);
|
|
2679
2907
|
}
|
|
2680
2908
|
onFeatureHover?.(feature, layerId);
|
|
2681
2909
|
});
|
|
2682
2910
|
layer.on("mouseout", () => {
|
|
2683
|
-
if (layer instanceof
|
|
2911
|
+
if (layer instanceof import_leaflet4.default.Path && originalStyle) {
|
|
2684
2912
|
layer.setStyle(originalStyle);
|
|
2685
2913
|
}
|
|
2686
|
-
if (layer instanceof
|
|
2914
|
+
if (layer instanceof import_leaflet4.default.CircleMarker && typeof originalRadius === "number") {
|
|
2687
2915
|
layer.setRadius(originalRadius);
|
|
2688
2916
|
}
|
|
2689
2917
|
});
|
|
@@ -2695,80 +2923,20 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2695
2923
|
const resolvedStyle = featureStyleOverrides ? { ...style ?? {}, ...featureStyleOverrides } : style;
|
|
2696
2924
|
const geometryType = feature?.geometry?.type;
|
|
2697
2925
|
const resolvedLayerType = layerType ?? geometryType;
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
resolvedLayerType
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
color: resolvedStyle?.color ?? resolvedStyle?.fillColor ?? "#2563eb",
|
|
2710
|
-
weight: resolvedStyle?.weight ?? 2,
|
|
2711
|
-
fillColor: resolvedStyle?.fillColor ?? resolvedStyle?.color ?? "#2563eb",
|
|
2712
|
-
opacity: strokeOpacity,
|
|
2713
|
-
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);
|
|
2714
2937
|
};
|
|
2715
2938
|
};
|
|
2716
|
-
|
|
2717
|
-
const size = 60;
|
|
2718
|
-
const innerSize = 44;
|
|
2719
|
-
const textStyles = getLabelTextStyles(color);
|
|
2720
|
-
const safeLabel = escapeHtml(label);
|
|
2721
|
-
const clampedOpacity = Math.min(1, Math.max(0.92, opacity));
|
|
2722
|
-
const innerBackground = withAlpha(color, 0.9);
|
|
2723
|
-
return import_leaflet.default.divIcon({
|
|
2724
|
-
className: "zenit-label-marker",
|
|
2725
|
-
iconSize: [size, size],
|
|
2726
|
-
iconAnchor: [size / 2, size / 2],
|
|
2727
|
-
html: `
|
|
2728
|
-
<div
|
|
2729
|
-
title="${safeLabel}"
|
|
2730
|
-
style="
|
|
2731
|
-
width:${size}px;
|
|
2732
|
-
height:${size}px;
|
|
2733
|
-
border-radius:9999px;
|
|
2734
|
-
background:rgba(255, 255, 255, 0.95);
|
|
2735
|
-
border:3px solid rgba(255, 255, 255, 1);
|
|
2736
|
-
display:flex;
|
|
2737
|
-
align-items:center;
|
|
2738
|
-
justify-content:center;
|
|
2739
|
-
opacity:${clampedOpacity};
|
|
2740
|
-
box-shadow:0 2px 6px rgba(0, 0, 0, 0.25);
|
|
2741
|
-
pointer-events:none;
|
|
2742
|
-
"
|
|
2743
|
-
>
|
|
2744
|
-
<div
|
|
2745
|
-
style="
|
|
2746
|
-
width:${innerSize}px;
|
|
2747
|
-
height:${innerSize}px;
|
|
2748
|
-
border-radius:9999px;
|
|
2749
|
-
background:${innerBackground};
|
|
2750
|
-
display:flex;
|
|
2751
|
-
align-items:center;
|
|
2752
|
-
justify-content:center;
|
|
2753
|
-
box-shadow:inset 0 0 0 1px rgba(15, 23, 42, 0.12);
|
|
2754
|
-
"
|
|
2755
|
-
>
|
|
2756
|
-
<span
|
|
2757
|
-
style="
|
|
2758
|
-
color:${textStyles.color};
|
|
2759
|
-
font-size:20px;
|
|
2760
|
-
font-weight:800;
|
|
2761
|
-
text-shadow:${textStyles.shadow};
|
|
2762
|
-
"
|
|
2763
|
-
>
|
|
2764
|
-
${safeLabel}
|
|
2765
|
-
</span>
|
|
2766
|
-
</div>
|
|
2767
|
-
</div>
|
|
2768
|
-
`
|
|
2769
|
-
});
|
|
2770
|
-
}, []);
|
|
2771
|
-
(0, import_react.useImperativeHandle)(ref, () => ({
|
|
2939
|
+
(0, import_react4.useImperativeHandle)(ref, () => ({
|
|
2772
2940
|
setLayerOpacity: (layerId, opacity) => {
|
|
2773
2941
|
upsertUiOverride(layerId, { overrideOpacity: opacity });
|
|
2774
2942
|
},
|
|
@@ -2818,10 +2986,10 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2818
2986
|
getMapInstance: () => mapInstance
|
|
2819
2987
|
}), [effectiveStates, mapInstance]);
|
|
2820
2988
|
if (loadingMap) {
|
|
2821
|
-
return /* @__PURE__ */ (0,
|
|
2989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { padding: 16, height, width }, children: "Cargando mapa..." });
|
|
2822
2990
|
}
|
|
2823
2991
|
if (mapError) {
|
|
2824
|
-
return /* @__PURE__ */ (0,
|
|
2992
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { padding: 16, height, width, color: "red" }, children: [
|
|
2825
2993
|
"Error al cargar mapa: ",
|
|
2826
2994
|
mapError
|
|
2827
2995
|
] });
|
|
@@ -2833,7 +3001,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2833
3001
|
setCurrentZoom(zoomValue);
|
|
2834
3002
|
onZoomChange?.(zoomValue);
|
|
2835
3003
|
};
|
|
2836
|
-
return /* @__PURE__ */ (0,
|
|
3004
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2837
3005
|
"div",
|
|
2838
3006
|
{
|
|
2839
3007
|
style: {
|
|
@@ -2846,13 +3014,13 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2846
3014
|
boxSizing: "border-box"
|
|
2847
3015
|
},
|
|
2848
3016
|
children: [
|
|
2849
|
-
/* @__PURE__ */ (0,
|
|
3017
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2850
3018
|
"div",
|
|
2851
3019
|
{
|
|
2852
3020
|
className: `zenit-map-shell${isPopupOpen ? " popup-open" : ""}`,
|
|
2853
3021
|
style: { flex: 1, position: "relative" },
|
|
2854
|
-
children: /* @__PURE__ */ (0,
|
|
2855
|
-
|
|
3022
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3023
|
+
import_react_leaflet4.MapContainer,
|
|
2856
3024
|
{
|
|
2857
3025
|
center,
|
|
2858
3026
|
zoom,
|
|
@@ -2860,57 +3028,68 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2860
3028
|
scrollWheelZoom: true,
|
|
2861
3029
|
zoomControl: false,
|
|
2862
3030
|
children: [
|
|
2863
|
-
/* @__PURE__ */ (0,
|
|
2864
|
-
|
|
3031
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3032
|
+
import_react_leaflet4.TileLayer,
|
|
2865
3033
|
{
|
|
2866
3034
|
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
2867
3035
|
attribution: "\xA9 OpenStreetMap contributors"
|
|
2868
3036
|
}
|
|
2869
3037
|
),
|
|
2870
|
-
/* @__PURE__ */ (0,
|
|
2871
|
-
/* @__PURE__ */ (0,
|
|
2872
|
-
/* @__PURE__ */ (0,
|
|
2873
|
-
|
|
2874
|
-
|
|
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,
|
|
3042
|
+
{
|
|
3043
|
+
bbox: zoomToBbox ?? void 0,
|
|
3044
|
+
geojson: zoomToGeojson ?? void 0,
|
|
3045
|
+
autoGeojson: autoZoomGeojson
|
|
3046
|
+
}
|
|
3047
|
+
),
|
|
3048
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ZoomBasedOpacityHandler, { onZoomChange: handleZoomChange }),
|
|
3049
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LocationControl, {}),
|
|
2875
3050
|
orderedLayers.map((layerState) => {
|
|
2876
3051
|
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
2877
3052
|
const fillPaneName = `zenit-layer-${layerState.mapLayer.layerId}-fill`;
|
|
2878
3053
|
const pointsPaneName = `zenit-layer-${layerState.mapLayer.layerId}-points`;
|
|
2879
3054
|
const layerType = layerState.layer?.layerType ?? layerState.mapLayer.layerType ?? void 0;
|
|
2880
|
-
const
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
2885
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.default.Fragment, { children: [
|
|
2886
|
-
fillData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2887
|
-
import_react_leaflet.GeoJSON,
|
|
2888
|
-
{
|
|
2889
|
-
data: fillData,
|
|
2890
|
-
pane: panesReady && mapInstance?.getPane(fillPaneName) ? fillPaneName : void 0,
|
|
2891
|
-
style: (feature) => buildLayerStyle(layerState.mapLayer.layerId, baseOpacity, feature, layerType),
|
|
2892
|
-
onEachFeature: overlayOnEachFeature
|
|
2893
|
-
}
|
|
2894
|
-
),
|
|
2895
|
-
pointsData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2896
|
-
import_react_leaflet.GeoJSON,
|
|
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,
|
|
2897
3059
|
{
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
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
|
|
2905
3084
|
}
|
|
2906
3085
|
),
|
|
2907
3086
|
panesReady && mapInstance?.getPane(LABELS_PANE_NAME) ? labelMarkers.filter(
|
|
2908
3087
|
(marker) => String(marker.layerId) === String(layerState.mapLayer.layerId)
|
|
2909
|
-
).map((marker) => /* @__PURE__ */ (0,
|
|
2910
|
-
|
|
3088
|
+
).map((marker) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3089
|
+
import_react_leaflet4.Marker,
|
|
2911
3090
|
{
|
|
2912
3091
|
position: marker.position,
|
|
2913
|
-
icon:
|
|
3092
|
+
icon: createCustomIcon(marker.label, marker.opacity, marker.color),
|
|
2914
3093
|
interactive: false,
|
|
2915
3094
|
pane: LABELS_PANE_NAME
|
|
2916
3095
|
},
|
|
@@ -2918,14 +3097,20 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2918
3097
|
)) : null
|
|
2919
3098
|
] }, layerState.mapLayer.layerId.toString());
|
|
2920
3099
|
}),
|
|
2921
|
-
overlayGeojson && /* @__PURE__ */ (0,
|
|
2922
|
-
|
|
3100
|
+
overlayGeojson && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3101
|
+
LayerGeoJson,
|
|
2923
3102
|
{
|
|
3103
|
+
layerId: "overlay-geojson",
|
|
2924
3104
|
data: overlayGeojson,
|
|
2925
|
-
|
|
3105
|
+
baseOpacity: 1,
|
|
3106
|
+
isMobile,
|
|
3107
|
+
panesReady,
|
|
3108
|
+
mapInstance,
|
|
3109
|
+
fillPaneName: "zenit-overlay-fill",
|
|
3110
|
+
pointsPaneName: "zenit-overlay-points",
|
|
3111
|
+
styleFn: overlayStyleFn,
|
|
2926
3112
|
onEachFeature: overlayOnEachFeature
|
|
2927
|
-
}
|
|
2928
|
-
"zenit-overlay-geojson"
|
|
3113
|
+
}
|
|
2929
3114
|
)
|
|
2930
3115
|
]
|
|
2931
3116
|
},
|
|
@@ -2933,7 +3118,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2933
3118
|
)
|
|
2934
3119
|
}
|
|
2935
3120
|
),
|
|
2936
|
-
showLayerPanel && decoratedLayers.length > 0 && /* @__PURE__ */ (0,
|
|
3121
|
+
showLayerPanel && decoratedLayers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2937
3122
|
"div",
|
|
2938
3123
|
{
|
|
2939
3124
|
style: {
|
|
@@ -2946,7 +3131,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2946
3131
|
overflowY: "auto"
|
|
2947
3132
|
},
|
|
2948
3133
|
children: [
|
|
2949
|
-
overlayGeojson && /* @__PURE__ */ (0,
|
|
3134
|
+
overlayGeojson && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2950
3135
|
"div",
|
|
2951
3136
|
{
|
|
2952
3137
|
style: {
|
|
@@ -2958,8 +3143,8 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2958
3143
|
marginBottom: 12
|
|
2959
3144
|
},
|
|
2960
3145
|
children: [
|
|
2961
|
-
/* @__PURE__ */ (0,
|
|
2962
|
-
/* @__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: [
|
|
2963
3148
|
"GeoJSON externo con ",
|
|
2964
3149
|
(overlayGeojson.features?.length ?? 0).toLocaleString(),
|
|
2965
3150
|
" elementos."
|
|
@@ -2967,14 +3152,14 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2967
3152
|
]
|
|
2968
3153
|
}
|
|
2969
3154
|
),
|
|
2970
|
-
/* @__PURE__ */ (0,
|
|
2971
|
-
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)(
|
|
2972
3157
|
"div",
|
|
2973
3158
|
{
|
|
2974
3159
|
style: { borderBottom: "1px solid #e5e7eb", paddingBottom: 10, marginBottom: 10 },
|
|
2975
3160
|
children: [
|
|
2976
|
-
/* @__PURE__ */ (0,
|
|
2977
|
-
/* @__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)(
|
|
2978
3163
|
"input",
|
|
2979
3164
|
{
|
|
2980
3165
|
type: "checkbox",
|
|
@@ -2985,17 +3170,17 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
2985
3170
|
}
|
|
2986
3171
|
}
|
|
2987
3172
|
),
|
|
2988
|
-
/* @__PURE__ */ (0,
|
|
3173
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: layerState.layer?.name ?? `Capa ${layerState.mapLayer.layerId}` })
|
|
2989
3174
|
] }),
|
|
2990
|
-
/* @__PURE__ */ (0,
|
|
2991
|
-
/* @__PURE__ */ (0,
|
|
2992
|
-
/* @__PURE__ */ (0,
|
|
2993
|
-
/* @__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: [
|
|
2994
3179
|
Math.round((layerState.effective?.opacity ?? 1) * 100),
|
|
2995
3180
|
"%"
|
|
2996
3181
|
] })
|
|
2997
3182
|
] }),
|
|
2998
|
-
/* @__PURE__ */ (0,
|
|
3183
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2999
3184
|
"input",
|
|
3000
3185
|
{
|
|
3001
3186
|
type: "range",
|
|
@@ -3025,13 +3210,13 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
3025
3210
|
ZenitMap.displayName = "ZenitMap";
|
|
3026
3211
|
|
|
3027
3212
|
// src/react/ZenitLayerManager.tsx
|
|
3028
|
-
var
|
|
3213
|
+
var import_react5 = __toESM(require("react"));
|
|
3029
3214
|
|
|
3030
3215
|
// src/react/icons.tsx
|
|
3031
3216
|
var import_lucide_react = require("lucide-react");
|
|
3032
3217
|
|
|
3033
3218
|
// src/react/ZenitLayerManager.tsx
|
|
3034
|
-
var
|
|
3219
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
3035
3220
|
var FLOAT_TOLERANCE = 1e-3;
|
|
3036
3221
|
function areEffectiveStatesEqual(a, b) {
|
|
3037
3222
|
if (a.length !== b.length) return false;
|
|
@@ -3071,15 +3256,15 @@ var ZenitLayerManager = ({
|
|
|
3071
3256
|
layerFeatureCounts,
|
|
3072
3257
|
mapLayers
|
|
3073
3258
|
}) => {
|
|
3074
|
-
const [map, setMap] = (0,
|
|
3075
|
-
const [loadingMap, setLoadingMap] = (0,
|
|
3076
|
-
const [mapError, setMapError] = (0,
|
|
3077
|
-
const [layers, setLayers] = (0,
|
|
3078
|
-
const [activeTab, setActiveTab] = (0,
|
|
3079
|
-
const [panelVisible, setPanelVisible] = (0,
|
|
3080
|
-
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);
|
|
3081
3266
|
const isControlled = Array.isArray(layerStates) && typeof onLayerStatesChange === "function";
|
|
3082
|
-
const baseStates = (0,
|
|
3267
|
+
const baseStates = (0, import_react5.useMemo)(
|
|
3083
3268
|
() => initLayerStates(
|
|
3084
3269
|
layers.map((entry) => ({
|
|
3085
3270
|
...entry.mapLayer,
|
|
@@ -3090,7 +3275,7 @@ var ZenitLayerManager = ({
|
|
|
3090
3275
|
),
|
|
3091
3276
|
[layers]
|
|
3092
3277
|
);
|
|
3093
|
-
const overrideStates = (0,
|
|
3278
|
+
const overrideStates = (0, import_react5.useMemo)(
|
|
3094
3279
|
() => layers.map(
|
|
3095
3280
|
(entry) => ({
|
|
3096
3281
|
layerId: entry.mapLayer.layerId,
|
|
@@ -3100,11 +3285,11 @@ var ZenitLayerManager = ({
|
|
|
3100
3285
|
),
|
|
3101
3286
|
[layers]
|
|
3102
3287
|
);
|
|
3103
|
-
const effectiveStates = (0,
|
|
3288
|
+
const effectiveStates = (0, import_react5.useMemo)(
|
|
3104
3289
|
() => layerStates ?? applyLayerOverrides(baseStates, overrideStates),
|
|
3105
3290
|
[baseStates, layerStates, overrideStates]
|
|
3106
3291
|
);
|
|
3107
|
-
const layerMetaIndex = (0,
|
|
3292
|
+
const layerMetaIndex = (0, import_react5.useMemo)(() => {
|
|
3108
3293
|
const index = /* @__PURE__ */ new Map();
|
|
3109
3294
|
mapLayers?.forEach((entry) => {
|
|
3110
3295
|
const key = String(entry.layerId);
|
|
@@ -3118,7 +3303,7 @@ var ZenitLayerManager = ({
|
|
|
3118
3303
|
});
|
|
3119
3304
|
return index;
|
|
3120
3305
|
}, [map, mapLayers]);
|
|
3121
|
-
const resolveUserOpacity =
|
|
3306
|
+
const resolveUserOpacity = import_react5.default.useCallback((state) => {
|
|
3122
3307
|
if (typeof state.overrideOpacity === "number") return state.overrideOpacity;
|
|
3123
3308
|
if (typeof state.overrideOpacity === "string") {
|
|
3124
3309
|
const parsed = Number.parseFloat(state.overrideOpacity);
|
|
@@ -3126,7 +3311,7 @@ var ZenitLayerManager = ({
|
|
|
3126
3311
|
}
|
|
3127
3312
|
return state.opacity ?? 1;
|
|
3128
3313
|
}, []);
|
|
3129
|
-
const resolveEffectiveOpacity =
|
|
3314
|
+
const resolveEffectiveOpacity = import_react5.default.useCallback(
|
|
3130
3315
|
(layerId, userOpacity) => {
|
|
3131
3316
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
3132
3317
|
return userOpacity;
|
|
@@ -3142,7 +3327,7 @@ var ZenitLayerManager = ({
|
|
|
3142
3327
|
},
|
|
3143
3328
|
[autoOpacityConfig, autoOpacityOnZoom, layerMetaIndex, mapZoom]
|
|
3144
3329
|
);
|
|
3145
|
-
const effectiveStatesWithZoom = (0,
|
|
3330
|
+
const effectiveStatesWithZoom = (0, import_react5.useMemo)(() => {
|
|
3146
3331
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
3147
3332
|
return effectiveStates;
|
|
3148
3333
|
}
|
|
@@ -3156,7 +3341,7 @@ var ZenitLayerManager = ({
|
|
|
3156
3341
|
};
|
|
3157
3342
|
});
|
|
3158
3343
|
}, [autoOpacityOnZoom, effectiveStates, mapZoom, resolveEffectiveOpacity, resolveUserOpacity]);
|
|
3159
|
-
(0,
|
|
3344
|
+
(0, import_react5.useEffect)(() => {
|
|
3160
3345
|
let cancelled = false;
|
|
3161
3346
|
setLoadingMap(true);
|
|
3162
3347
|
setMapError(null);
|
|
@@ -3188,12 +3373,12 @@ var ZenitLayerManager = ({
|
|
|
3188
3373
|
cancelled = true;
|
|
3189
3374
|
};
|
|
3190
3375
|
}, [client.maps, mapId]);
|
|
3191
|
-
(0,
|
|
3376
|
+
(0, import_react5.useEffect)(() => {
|
|
3192
3377
|
if (!showUploadTab && activeTab === "upload") {
|
|
3193
3378
|
setActiveTab("layers");
|
|
3194
3379
|
}
|
|
3195
3380
|
}, [activeTab, showUploadTab]);
|
|
3196
|
-
(0,
|
|
3381
|
+
(0, import_react5.useEffect)(() => {
|
|
3197
3382
|
if (isControlled) return;
|
|
3198
3383
|
if (!onLayerStatesChange) return;
|
|
3199
3384
|
const emitStates = autoOpacityOnZoom && typeof mapZoom === "number" ? effectiveStatesWithZoom : effectiveStates;
|
|
@@ -3211,7 +3396,7 @@ var ZenitLayerManager = ({
|
|
|
3211
3396
|
mapZoom,
|
|
3212
3397
|
onLayerStatesChange
|
|
3213
3398
|
]);
|
|
3214
|
-
const updateLayerVisible =
|
|
3399
|
+
const updateLayerVisible = import_react5.default.useCallback(
|
|
3215
3400
|
(layerId, visible) => {
|
|
3216
3401
|
if (!onLayerStatesChange) return;
|
|
3217
3402
|
const next = effectiveStates.map(
|
|
@@ -3221,7 +3406,7 @@ var ZenitLayerManager = ({
|
|
|
3221
3406
|
},
|
|
3222
3407
|
[effectiveStates, onLayerStatesChange]
|
|
3223
3408
|
);
|
|
3224
|
-
const updateLayerOpacity =
|
|
3409
|
+
const updateLayerOpacity = import_react5.default.useCallback(
|
|
3225
3410
|
(layerId, opacity) => {
|
|
3226
3411
|
if (!onLayerStatesChange) return;
|
|
3227
3412
|
const adjustedOpacity = resolveEffectiveOpacity(layerId, opacity);
|
|
@@ -3232,7 +3417,7 @@ var ZenitLayerManager = ({
|
|
|
3232
3417
|
},
|
|
3233
3418
|
[effectiveStates, onLayerStatesChange, resolveEffectiveOpacity]
|
|
3234
3419
|
);
|
|
3235
|
-
const resolveFeatureCount =
|
|
3420
|
+
const resolveFeatureCount = import_react5.default.useCallback(
|
|
3236
3421
|
(layerId, layer) => {
|
|
3237
3422
|
const resolvedFeatureCount = layerFeatureCounts?.[layerId] ?? layerFeatureCounts?.[String(layerId)];
|
|
3238
3423
|
if (typeof resolvedFeatureCount === "number") return resolvedFeatureCount;
|
|
@@ -3241,7 +3426,7 @@ var ZenitLayerManager = ({
|
|
|
3241
3426
|
},
|
|
3242
3427
|
[layerFeatureCounts]
|
|
3243
3428
|
);
|
|
3244
|
-
const decoratedLayers = (0,
|
|
3429
|
+
const decoratedLayers = (0, import_react5.useMemo)(() => {
|
|
3245
3430
|
return layers.map((entry) => ({
|
|
3246
3431
|
...entry,
|
|
3247
3432
|
effective: effectiveStates.find((state) => state.layerId === entry.mapLayer.layerId),
|
|
@@ -3270,7 +3455,7 @@ var ZenitLayerManager = ({
|
|
|
3270
3455
|
return String(a.mapLayer.layerId).localeCompare(String(b.mapLayer.layerId));
|
|
3271
3456
|
});
|
|
3272
3457
|
}, [effectiveStates, layers, resolveFeatureCount]);
|
|
3273
|
-
const resolveLayerStyle =
|
|
3458
|
+
const resolveLayerStyle = import_react5.default.useCallback(
|
|
3274
3459
|
(layerId) => {
|
|
3275
3460
|
const layerKey = String(layerId);
|
|
3276
3461
|
const fromProp = mapLayers?.find((entry) => String(entry.layerId) === layerKey)?.style;
|
|
@@ -3300,10 +3485,10 @@ var ZenitLayerManager = ({
|
|
|
3300
3485
|
...height ? { height } : {}
|
|
3301
3486
|
};
|
|
3302
3487
|
if (loadingMap) {
|
|
3303
|
-
return /* @__PURE__ */ (0,
|
|
3488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: panelStyle, children: "Cargando capas\u2026" });
|
|
3304
3489
|
}
|
|
3305
3490
|
if (mapError) {
|
|
3306
|
-
return /* @__PURE__ */ (0,
|
|
3491
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className, style: { ...panelStyle, color: "#c53030" }, children: [
|
|
3307
3492
|
"Error al cargar mapa: ",
|
|
3308
3493
|
mapError
|
|
3309
3494
|
] });
|
|
@@ -3321,7 +3506,7 @@ var ZenitLayerManager = ({
|
|
|
3321
3506
|
boxShadow: "0 1px 0 rgba(148, 163, 184, 0.25)"
|
|
3322
3507
|
};
|
|
3323
3508
|
const renderLayerCards = () => {
|
|
3324
|
-
return /* @__PURE__ */ (0,
|
|
3509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: decoratedLayers.map((layerState) => {
|
|
3325
3510
|
const layerId = layerState.mapLayer.layerId;
|
|
3326
3511
|
const layerName = layerState.layerName ?? `Capa ${layerId}`;
|
|
3327
3512
|
const visible = layerState.effective?.visible ?? false;
|
|
@@ -3331,7 +3516,7 @@ var ZenitLayerManager = ({
|
|
|
3331
3516
|
const muted = !visible;
|
|
3332
3517
|
const opacityPercent = Math.round(userOpacity * 100);
|
|
3333
3518
|
const sliderBackground = `linear-gradient(to right, ${layerColor} 0%, ${layerColor} ${opacityPercent}%, #e5e7eb ${opacityPercent}%, #e5e7eb 100%)`;
|
|
3334
|
-
return /* @__PURE__ */ (0,
|
|
3519
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3335
3520
|
"div",
|
|
3336
3521
|
{
|
|
3337
3522
|
className: `zlm-card${muted ? " is-muted" : ""}`,
|
|
@@ -3346,9 +3531,9 @@ var ZenitLayerManager = ({
|
|
|
3346
3531
|
width: "100%"
|
|
3347
3532
|
},
|
|
3348
3533
|
children: [
|
|
3349
|
-
/* @__PURE__ */ (0,
|
|
3350
|
-
/* @__PURE__ */ (0,
|
|
3351
|
-
/* @__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)(
|
|
3352
3537
|
"div",
|
|
3353
3538
|
{
|
|
3354
3539
|
style: {
|
|
@@ -3363,7 +3548,7 @@ var ZenitLayerManager = ({
|
|
|
3363
3548
|
title: "Color de la capa"
|
|
3364
3549
|
}
|
|
3365
3550
|
),
|
|
3366
|
-
showLayerVisibilityIcon && /* @__PURE__ */ (0,
|
|
3551
|
+
showLayerVisibilityIcon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3367
3552
|
"button",
|
|
3368
3553
|
{
|
|
3369
3554
|
type: "button",
|
|
@@ -3374,11 +3559,11 @@ var ZenitLayerManager = ({
|
|
|
3374
3559
|
)
|
|
3375
3560
|
),
|
|
3376
3561
|
"aria-label": visible ? "Ocultar capa" : "Mostrar capa",
|
|
3377
|
-
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 })
|
|
3378
3563
|
}
|
|
3379
3564
|
),
|
|
3380
|
-
/* @__PURE__ */ (0,
|
|
3381
|
-
/* @__PURE__ */ (0,
|
|
3565
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { minWidth: 0, flex: 1 }, children: [
|
|
3566
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3382
3567
|
"div",
|
|
3383
3568
|
{
|
|
3384
3569
|
className: "zlm-layer-name",
|
|
@@ -3396,26 +3581,26 @@ var ZenitLayerManager = ({
|
|
|
3396
3581
|
children: layerName
|
|
3397
3582
|
}
|
|
3398
3583
|
),
|
|
3399
|
-
/* @__PURE__ */ (0,
|
|
3584
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: muted ? "#94a3b8" : "#64748b", fontSize: 12 }, children: [
|
|
3400
3585
|
"ID ",
|
|
3401
3586
|
layerId
|
|
3402
3587
|
] })
|
|
3403
3588
|
] })
|
|
3404
3589
|
] }),
|
|
3405
|
-
/* @__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: [
|
|
3406
3591
|
featureCount.toLocaleString(),
|
|
3407
3592
|
" features"
|
|
3408
3593
|
] }) })
|
|
3409
3594
|
] }),
|
|
3410
|
-
/* @__PURE__ */ (0,
|
|
3411
|
-
/* @__PURE__ */ (0,
|
|
3412
|
-
/* @__PURE__ */ (0,
|
|
3413
|
-
/* @__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: [
|
|
3414
3599
|
opacityPercent,
|
|
3415
3600
|
"%"
|
|
3416
3601
|
] })
|
|
3417
3602
|
] }),
|
|
3418
|
-
/* @__PURE__ */ (0,
|
|
3603
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3419
3604
|
"input",
|
|
3420
3605
|
{
|
|
3421
3606
|
className: "zlm-range",
|
|
@@ -3453,8 +3638,8 @@ var ZenitLayerManager = ({
|
|
|
3453
3638
|
);
|
|
3454
3639
|
}) });
|
|
3455
3640
|
};
|
|
3456
|
-
return /* @__PURE__ */ (0,
|
|
3457
|
-
/* @__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: `
|
|
3458
3643
|
.zenit-layer-manager .zlm-card {
|
|
3459
3644
|
transition: box-shadow 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
|
|
3460
3645
|
box-shadow: 0 6px 16px rgba(15, 23, 42, 0.08);
|
|
@@ -3549,16 +3734,16 @@ var ZenitLayerManager = ({
|
|
|
3549
3734
|
outline-offset: 2px;
|
|
3550
3735
|
}
|
|
3551
3736
|
` }),
|
|
3552
|
-
/* @__PURE__ */ (0,
|
|
3553
|
-
/* @__PURE__ */ (0,
|
|
3554
|
-
/* @__PURE__ */ (0,
|
|
3555
|
-
/* @__PURE__ */ (0,
|
|
3556
|
-
/* @__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: [
|
|
3557
3742
|
"Mapa #",
|
|
3558
3743
|
map.id
|
|
3559
3744
|
] })
|
|
3560
3745
|
] }),
|
|
3561
|
-
/* @__PURE__ */ (0,
|
|
3746
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3562
3747
|
"button",
|
|
3563
3748
|
{
|
|
3564
3749
|
type: "button",
|
|
@@ -3566,13 +3751,13 @@ var ZenitLayerManager = ({
|
|
|
3566
3751
|
className: "zlm-panel-toggle",
|
|
3567
3752
|
"aria-label": panelVisible ? "Ocultar panel de capas" : "Mostrar panel de capas",
|
|
3568
3753
|
children: [
|
|
3569
|
-
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 }),
|
|
3570
3755
|
panelVisible ? "Ocultar" : "Mostrar"
|
|
3571
3756
|
]
|
|
3572
3757
|
}
|
|
3573
3758
|
)
|
|
3574
3759
|
] }),
|
|
3575
|
-
/* @__PURE__ */ (0,
|
|
3760
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3576
3761
|
"div",
|
|
3577
3762
|
{
|
|
3578
3763
|
style: {
|
|
@@ -3585,26 +3770,26 @@ var ZenitLayerManager = ({
|
|
|
3585
3770
|
background: "#f1f5f9"
|
|
3586
3771
|
},
|
|
3587
3772
|
children: [
|
|
3588
|
-
/* @__PURE__ */ (0,
|
|
3773
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3589
3774
|
"button",
|
|
3590
3775
|
{
|
|
3591
3776
|
type: "button",
|
|
3592
3777
|
className: `zlm-tab${activeTab === "layers" ? " is-active" : ""}`,
|
|
3593
3778
|
onClick: () => setActiveTab("layers"),
|
|
3594
3779
|
children: [
|
|
3595
|
-
/* @__PURE__ */ (0,
|
|
3780
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Layers, { size: 16 }),
|
|
3596
3781
|
"Capas"
|
|
3597
3782
|
]
|
|
3598
3783
|
}
|
|
3599
3784
|
),
|
|
3600
|
-
showUploadTab && /* @__PURE__ */ (0,
|
|
3785
|
+
showUploadTab && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3601
3786
|
"button",
|
|
3602
3787
|
{
|
|
3603
3788
|
type: "button",
|
|
3604
3789
|
className: `zlm-tab${activeTab === "upload" ? " is-active" : ""}`,
|
|
3605
3790
|
onClick: () => setActiveTab("upload"),
|
|
3606
3791
|
children: [
|
|
3607
|
-
/* @__PURE__ */ (0,
|
|
3792
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Upload, { size: 16 }),
|
|
3608
3793
|
"Subir"
|
|
3609
3794
|
]
|
|
3610
3795
|
}
|
|
@@ -3613,15 +3798,15 @@ var ZenitLayerManager = ({
|
|
|
3613
3798
|
}
|
|
3614
3799
|
)
|
|
3615
3800
|
] }),
|
|
3616
|
-
panelVisible && /* @__PURE__ */ (0,
|
|
3801
|
+
panelVisible && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
|
|
3617
3802
|
activeTab === "layers" && renderLayerCards(),
|
|
3618
|
-
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." })
|
|
3619
3804
|
] })
|
|
3620
3805
|
] });
|
|
3621
3806
|
};
|
|
3622
3807
|
|
|
3623
3808
|
// src/react/ZenitFeatureFilterPanel.tsx
|
|
3624
|
-
var
|
|
3809
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
3625
3810
|
var ZenitFeatureFilterPanel = ({
|
|
3626
3811
|
title = "Filtros",
|
|
3627
3812
|
description,
|
|
@@ -3629,7 +3814,7 @@ var ZenitFeatureFilterPanel = ({
|
|
|
3629
3814
|
style,
|
|
3630
3815
|
children
|
|
3631
3816
|
}) => {
|
|
3632
|
-
return /* @__PURE__ */ (0,
|
|
3817
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3633
3818
|
"section",
|
|
3634
3819
|
{
|
|
3635
3820
|
className,
|
|
@@ -3642,26 +3827,26 @@ var ZenitFeatureFilterPanel = ({
|
|
|
3642
3827
|
...style
|
|
3643
3828
|
},
|
|
3644
3829
|
children: [
|
|
3645
|
-
/* @__PURE__ */ (0,
|
|
3646
|
-
/* @__PURE__ */ (0,
|
|
3647
|
-
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 })
|
|
3648
3833
|
] }),
|
|
3649
|
-
/* @__PURE__ */ (0,
|
|
3834
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children })
|
|
3650
3835
|
]
|
|
3651
3836
|
}
|
|
3652
3837
|
);
|
|
3653
3838
|
};
|
|
3654
3839
|
|
|
3655
3840
|
// src/react/ai/FloatingChatBox.tsx
|
|
3656
|
-
var
|
|
3657
|
-
var
|
|
3841
|
+
var import_react7 = require("react");
|
|
3842
|
+
var import_react_dom2 = require("react-dom");
|
|
3658
3843
|
|
|
3659
3844
|
// src/react/hooks/use-chat.ts
|
|
3660
|
-
var
|
|
3845
|
+
var import_react6 = require("react");
|
|
3661
3846
|
var useSendMessage = (config) => {
|
|
3662
|
-
const [isLoading, setIsLoading] = (0,
|
|
3663
|
-
const [error, setError] = (0,
|
|
3664
|
-
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)(
|
|
3665
3850
|
async (mapId, request, options) => {
|
|
3666
3851
|
setIsLoading(true);
|
|
3667
3852
|
setError(null);
|
|
@@ -3679,18 +3864,18 @@ var useSendMessage = (config) => {
|
|
|
3679
3864
|
return { sendMessage: send, isLoading, error };
|
|
3680
3865
|
};
|
|
3681
3866
|
var useSendMessageStream = (config) => {
|
|
3682
|
-
const [isStreaming, setIsStreaming] = (0,
|
|
3683
|
-
const [streamingText, setStreamingText] = (0,
|
|
3684
|
-
const [completeResponse, setCompleteResponse] = (0,
|
|
3685
|
-
const [error, setError] = (0,
|
|
3686
|
-
const requestIdRef = (0,
|
|
3687
|
-
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)(() => {
|
|
3688
3873
|
setIsStreaming(false);
|
|
3689
3874
|
setStreamingText("");
|
|
3690
3875
|
setCompleteResponse(null);
|
|
3691
3876
|
setError(null);
|
|
3692
3877
|
}, []);
|
|
3693
|
-
const send = (0,
|
|
3878
|
+
const send = (0, import_react6.useCallback)(
|
|
3694
3879
|
async (mapId, request, options) => {
|
|
3695
3880
|
const requestId = requestIdRef.current + 1;
|
|
3696
3881
|
requestIdRef.current = requestId;
|
|
@@ -3744,7 +3929,7 @@ var useSendMessageStream = (config) => {
|
|
|
3744
3929
|
// src/react/components/MarkdownRenderer.tsx
|
|
3745
3930
|
var import_react_markdown = __toESM(require("react-markdown"));
|
|
3746
3931
|
var import_remark_gfm = __toESM(require("remark-gfm"));
|
|
3747
|
-
var
|
|
3932
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
3748
3933
|
function normalizeAssistantMarkdown(text) {
|
|
3749
3934
|
if (!text || typeof text !== "string") return "";
|
|
3750
3935
|
let normalized = text;
|
|
@@ -3760,28 +3945,28 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3760
3945
|
if (!normalizedContent) {
|
|
3761
3946
|
return null;
|
|
3762
3947
|
}
|
|
3763
|
-
return /* @__PURE__ */ (0,
|
|
3948
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className, style: { wordBreak: "break-word" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3764
3949
|
import_react_markdown.default,
|
|
3765
3950
|
{
|
|
3766
3951
|
remarkPlugins: [import_remark_gfm.default],
|
|
3767
3952
|
components: {
|
|
3768
3953
|
// Headings with proper spacing
|
|
3769
|
-
h1: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3770
|
-
h2: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3771
|
-
h3: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3772
|
-
h4: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3773
|
-
h5: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3774
|
-
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 }),
|
|
3775
3960
|
// Paragraphs with comfortable line height
|
|
3776
|
-
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 }),
|
|
3777
3962
|
// Lists with proper indentation
|
|
3778
|
-
ul: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3779
|
-
ol: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
3780
|
-
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 }),
|
|
3781
3966
|
// Code blocks
|
|
3782
3967
|
code: ({ inline, children, ...props }) => {
|
|
3783
3968
|
if (inline) {
|
|
3784
|
-
return /* @__PURE__ */ (0,
|
|
3969
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3785
3970
|
"code",
|
|
3786
3971
|
{
|
|
3787
3972
|
style: {
|
|
@@ -3796,7 +3981,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3796
3981
|
}
|
|
3797
3982
|
);
|
|
3798
3983
|
}
|
|
3799
|
-
return /* @__PURE__ */ (0,
|
|
3984
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3800
3985
|
"code",
|
|
3801
3986
|
{
|
|
3802
3987
|
style: {
|
|
@@ -3816,9 +4001,9 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3816
4001
|
);
|
|
3817
4002
|
},
|
|
3818
4003
|
// Pre (code block wrapper)
|
|
3819
|
-
pre: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4004
|
+
pre: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { style: { margin: 0 }, ...props, children }),
|
|
3820
4005
|
// Blockquotes
|
|
3821
|
-
blockquote: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4006
|
+
blockquote: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3822
4007
|
"blockquote",
|
|
3823
4008
|
{
|
|
3824
4009
|
style: {
|
|
@@ -3834,11 +4019,11 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3834
4019
|
}
|
|
3835
4020
|
),
|
|
3836
4021
|
// Strong/bold
|
|
3837
|
-
strong: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4022
|
+
strong: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { style: { fontWeight: 600 }, ...props, children }),
|
|
3838
4023
|
// Emphasis/italic
|
|
3839
|
-
em: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4024
|
+
em: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("em", { style: { fontStyle: "italic" }, ...props, children }),
|
|
3840
4025
|
// Horizontal rule
|
|
3841
|
-
hr: (props) => /* @__PURE__ */ (0,
|
|
4026
|
+
hr: (props) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3842
4027
|
"hr",
|
|
3843
4028
|
{
|
|
3844
4029
|
style: {
|
|
@@ -3851,7 +4036,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3851
4036
|
}
|
|
3852
4037
|
),
|
|
3853
4038
|
// Tables (GFM)
|
|
3854
|
-
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)(
|
|
3855
4040
|
"table",
|
|
3856
4041
|
{
|
|
3857
4042
|
style: {
|
|
@@ -3863,7 +4048,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3863
4048
|
children
|
|
3864
4049
|
}
|
|
3865
4050
|
) }),
|
|
3866
|
-
th: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4051
|
+
th: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3867
4052
|
"th",
|
|
3868
4053
|
{
|
|
3869
4054
|
style: {
|
|
@@ -3877,7 +4062,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3877
4062
|
children
|
|
3878
4063
|
}
|
|
3879
4064
|
),
|
|
3880
|
-
td: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
4065
|
+
td: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3881
4066
|
"td",
|
|
3882
4067
|
{
|
|
3883
4068
|
style: {
|
|
@@ -3895,32 +4080,32 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
3895
4080
|
};
|
|
3896
4081
|
|
|
3897
4082
|
// src/react/ai/FloatingChatBox.tsx
|
|
3898
|
-
var
|
|
3899
|
-
var ChatIcon = () => /* @__PURE__ */ (0,
|
|
3900
|
-
var CloseIcon = () => /* @__PURE__ */ (0,
|
|
3901
|
-
/* @__PURE__ */ (0,
|
|
3902
|
-
/* @__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" })
|
|
3903
4088
|
] });
|
|
3904
|
-
var ExpandIcon = () => /* @__PURE__ */ (0,
|
|
3905
|
-
/* @__PURE__ */ (0,
|
|
3906
|
-
/* @__PURE__ */ (0,
|
|
3907
|
-
/* @__PURE__ */ (0,
|
|
3908
|
-
/* @__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" })
|
|
3909
4094
|
] });
|
|
3910
|
-
var CollapseIcon = () => /* @__PURE__ */ (0,
|
|
3911
|
-
/* @__PURE__ */ (0,
|
|
3912
|
-
/* @__PURE__ */ (0,
|
|
3913
|
-
/* @__PURE__ */ (0,
|
|
3914
|
-
/* @__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" })
|
|
3915
4100
|
] });
|
|
3916
|
-
var SendIcon = () => /* @__PURE__ */ (0,
|
|
3917
|
-
/* @__PURE__ */ (0,
|
|
3918
|
-
/* @__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" })
|
|
3919
4104
|
] });
|
|
3920
|
-
var LayersIcon = () => /* @__PURE__ */ (0,
|
|
3921
|
-
/* @__PURE__ */ (0,
|
|
3922
|
-
/* @__PURE__ */ (0,
|
|
3923
|
-
/* @__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" })
|
|
3924
4109
|
] });
|
|
3925
4110
|
var styles = {
|
|
3926
4111
|
root: {
|
|
@@ -3929,8 +4114,8 @@ var styles = {
|
|
|
3929
4114
|
// Floating button (closed state - wide with text, open state - circular with X)
|
|
3930
4115
|
floatingButton: {
|
|
3931
4116
|
position: "fixed",
|
|
3932
|
-
bottom:
|
|
3933
|
-
right:
|
|
4117
|
+
bottom: 16,
|
|
4118
|
+
right: 16,
|
|
3934
4119
|
borderRadius: "999px",
|
|
3935
4120
|
border: "none",
|
|
3936
4121
|
cursor: "pointer",
|
|
@@ -3940,30 +4125,30 @@ var styles = {
|
|
|
3940
4125
|
display: "flex",
|
|
3941
4126
|
alignItems: "center",
|
|
3942
4127
|
justifyContent: "center",
|
|
3943
|
-
fontSize:
|
|
4128
|
+
fontSize: 14,
|
|
3944
4129
|
fontWeight: 600,
|
|
3945
4130
|
zIndex: 99999,
|
|
3946
4131
|
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
|
|
3947
4132
|
},
|
|
3948
4133
|
floatingButtonClosed: {
|
|
3949
|
-
padding: "
|
|
4134
|
+
padding: "12px 20px",
|
|
3950
4135
|
gap: 8
|
|
3951
4136
|
},
|
|
3952
4137
|
floatingButtonOpen: {
|
|
3953
|
-
width:
|
|
3954
|
-
height:
|
|
4138
|
+
width: 52,
|
|
4139
|
+
height: 52,
|
|
3955
4140
|
padding: 0
|
|
3956
4141
|
},
|
|
3957
4142
|
floatingButtonMobile: {
|
|
3958
|
-
width:
|
|
3959
|
-
height:
|
|
4143
|
+
width: 52,
|
|
4144
|
+
height: 52,
|
|
3960
4145
|
padding: 0
|
|
3961
4146
|
},
|
|
3962
4147
|
// Panel (expandable)
|
|
3963
4148
|
panel: {
|
|
3964
4149
|
position: "fixed",
|
|
3965
|
-
bottom:
|
|
3966
|
-
right:
|
|
4150
|
+
bottom: 80,
|
|
4151
|
+
right: 16,
|
|
3967
4152
|
background: "#fff",
|
|
3968
4153
|
borderRadius: 16,
|
|
3969
4154
|
boxShadow: "0 20px 60px rgba(15, 23, 42, 0.3), 0 0 0 1px rgba(15, 23, 42, 0.05)",
|
|
@@ -3974,16 +4159,16 @@ var styles = {
|
|
|
3974
4159
|
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
|
|
3975
4160
|
},
|
|
3976
4161
|
panelNormal: {
|
|
3977
|
-
width:
|
|
3978
|
-
height:
|
|
4162
|
+
width: 360,
|
|
4163
|
+
height: 520
|
|
3979
4164
|
},
|
|
3980
4165
|
panelExpanded: {
|
|
3981
|
-
width:
|
|
3982
|
-
height:
|
|
4166
|
+
width: 480,
|
|
4167
|
+
height: 640
|
|
3983
4168
|
},
|
|
3984
4169
|
// Header with green gradient
|
|
3985
4170
|
header: {
|
|
3986
|
-
padding: "16px
|
|
4171
|
+
padding: "14px 16px",
|
|
3987
4172
|
background: "linear-gradient(135deg, #10b981, #059669)",
|
|
3988
4173
|
color: "#fff",
|
|
3989
4174
|
display: "flex",
|
|
@@ -3992,7 +4177,7 @@ var styles = {
|
|
|
3992
4177
|
},
|
|
3993
4178
|
title: {
|
|
3994
4179
|
margin: 0,
|
|
3995
|
-
fontSize:
|
|
4180
|
+
fontSize: 15,
|
|
3996
4181
|
fontWeight: 600,
|
|
3997
4182
|
letterSpacing: "-0.01em"
|
|
3998
4183
|
},
|
|
@@ -4005,8 +4190,8 @@ var styles = {
|
|
|
4005
4190
|
border: "none",
|
|
4006
4191
|
background: "rgba(255, 255, 255, 0.15)",
|
|
4007
4192
|
color: "#fff",
|
|
4008
|
-
width:
|
|
4009
|
-
height:
|
|
4193
|
+
width: 30,
|
|
4194
|
+
height: 30,
|
|
4010
4195
|
borderRadius: 8,
|
|
4011
4196
|
cursor: "pointer",
|
|
4012
4197
|
display: "flex",
|
|
@@ -4017,7 +4202,7 @@ var styles = {
|
|
|
4017
4202
|
// Messages area
|
|
4018
4203
|
messages: {
|
|
4019
4204
|
flex: 1,
|
|
4020
|
-
padding: "
|
|
4205
|
+
padding: "16px",
|
|
4021
4206
|
overflowY: "auto",
|
|
4022
4207
|
background: "#f8fafc",
|
|
4023
4208
|
display: "flex",
|
|
@@ -4032,10 +4217,10 @@ var styles = {
|
|
|
4032
4217
|
},
|
|
4033
4218
|
messageBubble: {
|
|
4034
4219
|
maxWidth: "85%",
|
|
4035
|
-
padding: "12px
|
|
4220
|
+
padding: "10px 12px",
|
|
4036
4221
|
borderRadius: 16,
|
|
4037
4222
|
lineHeight: 1.5,
|
|
4038
|
-
fontSize:
|
|
4223
|
+
fontSize: 13,
|
|
4039
4224
|
whiteSpace: "pre-wrap",
|
|
4040
4225
|
wordBreak: "break-word"
|
|
4041
4226
|
},
|
|
@@ -4149,7 +4334,7 @@ var styles = {
|
|
|
4149
4334
|
// Input area
|
|
4150
4335
|
inputWrapper: {
|
|
4151
4336
|
borderTop: "1px solid #e2e8f0",
|
|
4152
|
-
padding: "14px
|
|
4337
|
+
padding: "10px 14px",
|
|
4153
4338
|
display: "flex",
|
|
4154
4339
|
gap: 10,
|
|
4155
4340
|
alignItems: "flex-end",
|
|
@@ -4160,8 +4345,8 @@ var styles = {
|
|
|
4160
4345
|
resize: "none",
|
|
4161
4346
|
borderRadius: 12,
|
|
4162
4347
|
border: "1.5px solid #cbd5e1",
|
|
4163
|
-
padding: "10px
|
|
4164
|
-
fontSize:
|
|
4348
|
+
padding: "8px 10px",
|
|
4349
|
+
fontSize: 13,
|
|
4165
4350
|
fontFamily: "inherit",
|
|
4166
4351
|
lineHeight: 1.4,
|
|
4167
4352
|
transition: "border-color 0.2s"
|
|
@@ -4173,18 +4358,18 @@ var styles = {
|
|
|
4173
4358
|
sendButton: {
|
|
4174
4359
|
borderRadius: 12,
|
|
4175
4360
|
border: "none",
|
|
4176
|
-
padding: "
|
|
4361
|
+
padding: "8px 12px",
|
|
4177
4362
|
background: "linear-gradient(135deg, #10b981, #059669)",
|
|
4178
4363
|
color: "#fff",
|
|
4179
4364
|
cursor: "pointer",
|
|
4180
|
-
fontSize:
|
|
4365
|
+
fontSize: 13,
|
|
4181
4366
|
fontWeight: 600,
|
|
4182
4367
|
display: "flex",
|
|
4183
4368
|
alignItems: "center",
|
|
4184
4369
|
justifyContent: "center",
|
|
4185
4370
|
transition: "opacity 0.2s, transform 0.2s",
|
|
4186
|
-
minWidth:
|
|
4187
|
-
height:
|
|
4371
|
+
minWidth: 40,
|
|
4372
|
+
height: 40
|
|
4188
4373
|
},
|
|
4189
4374
|
// Status messages
|
|
4190
4375
|
statusNote: {
|
|
@@ -4214,42 +4399,42 @@ var FloatingChatBox = ({
|
|
|
4214
4399
|
open: openProp
|
|
4215
4400
|
}) => {
|
|
4216
4401
|
const isControlled = openProp !== void 0;
|
|
4217
|
-
const [internalOpen, setInternalOpen] = (0,
|
|
4402
|
+
const [internalOpen, setInternalOpen] = (0, import_react7.useState)(false);
|
|
4218
4403
|
const open = isControlled ? openProp : internalOpen;
|
|
4219
|
-
const setOpen = (0,
|
|
4404
|
+
const setOpen = (0, import_react7.useCallback)((value) => {
|
|
4220
4405
|
const newValue = typeof value === "function" ? value(open) : value;
|
|
4221
4406
|
if (!isControlled) {
|
|
4222
4407
|
setInternalOpen(newValue);
|
|
4223
4408
|
}
|
|
4224
4409
|
onOpenChange?.(newValue);
|
|
4225
4410
|
}, [isControlled, open, onOpenChange]);
|
|
4226
|
-
const [expanded, setExpanded] = (0,
|
|
4227
|
-
const [messages, setMessages] = (0,
|
|
4228
|
-
const [inputValue, setInputValue] = (0,
|
|
4229
|
-
const [conversationId, setConversationId] = (0,
|
|
4230
|
-
const [errorMessage, setErrorMessage] = (0,
|
|
4231
|
-
const [isFocused, setIsFocused] = (0,
|
|
4232
|
-
const [isMobile, setIsMobile] = (0,
|
|
4233
|
-
const messagesEndRef = (0,
|
|
4234
|
-
const messagesContainerRef = (0,
|
|
4235
|
-
const chatBoxRef = (0,
|
|
4236
|
-
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)(() => {
|
|
4237
4422
|
if (!baseUrl) return void 0;
|
|
4238
4423
|
return { baseUrl, accessToken, getAccessToken };
|
|
4239
4424
|
}, [accessToken, baseUrl, getAccessToken]);
|
|
4240
4425
|
const { sendMessage: sendMessage2, isStreaming, streamingText, completeResponse } = useSendMessageStream(chatConfig);
|
|
4241
4426
|
const canSend = Boolean(mapId) && Boolean(baseUrl) && inputValue.trim().length > 0 && !isStreaming;
|
|
4242
|
-
(0,
|
|
4427
|
+
(0, import_react7.useEffect)(() => {
|
|
4243
4428
|
if (open && isMobile) {
|
|
4244
4429
|
setExpanded(true);
|
|
4245
4430
|
}
|
|
4246
4431
|
}, [open, isMobile]);
|
|
4247
|
-
const scrollToBottom = (0,
|
|
4432
|
+
const scrollToBottom = (0, import_react7.useCallback)(() => {
|
|
4248
4433
|
if (messagesEndRef.current) {
|
|
4249
4434
|
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
4250
4435
|
}
|
|
4251
4436
|
}, []);
|
|
4252
|
-
(0,
|
|
4437
|
+
(0, import_react7.useEffect)(() => {
|
|
4253
4438
|
if (open && messages.length === 0) {
|
|
4254
4439
|
setMessages([
|
|
4255
4440
|
{
|
|
@@ -4260,10 +4445,10 @@ var FloatingChatBox = ({
|
|
|
4260
4445
|
]);
|
|
4261
4446
|
}
|
|
4262
4447
|
}, [open, messages.length]);
|
|
4263
|
-
(0,
|
|
4448
|
+
(0, import_react7.useEffect)(() => {
|
|
4264
4449
|
scrollToBottom();
|
|
4265
4450
|
}, [messages, streamingText, scrollToBottom]);
|
|
4266
|
-
(0,
|
|
4451
|
+
(0, import_react7.useEffect)(() => {
|
|
4267
4452
|
if (!open) return;
|
|
4268
4453
|
if (isMobile && expanded) return;
|
|
4269
4454
|
const handleClickOutside = (event) => {
|
|
@@ -4276,7 +4461,7 @@ var FloatingChatBox = ({
|
|
|
4276
4461
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
4277
4462
|
};
|
|
4278
4463
|
}, [open, isMobile, expanded]);
|
|
4279
|
-
(0,
|
|
4464
|
+
(0, import_react7.useEffect)(() => {
|
|
4280
4465
|
if (typeof window === "undefined") return;
|
|
4281
4466
|
const mediaQuery = window.matchMedia("(max-width: 768px)");
|
|
4282
4467
|
const updateMobile = () => setIsMobile(mediaQuery.matches);
|
|
@@ -4294,7 +4479,7 @@ var FloatingChatBox = ({
|
|
|
4294
4479
|
}
|
|
4295
4480
|
};
|
|
4296
4481
|
}, []);
|
|
4297
|
-
(0,
|
|
4482
|
+
(0, import_react7.useEffect)(() => {
|
|
4298
4483
|
if (typeof document === "undefined") return;
|
|
4299
4484
|
if (!open || !isMobile) return;
|
|
4300
4485
|
document.body.style.overflow = "hidden";
|
|
@@ -4302,10 +4487,10 @@ var FloatingChatBox = ({
|
|
|
4302
4487
|
document.body.style.overflow = "";
|
|
4303
4488
|
};
|
|
4304
4489
|
}, [open, isMobile]);
|
|
4305
|
-
const addMessage = (0,
|
|
4490
|
+
const addMessage = (0, import_react7.useCallback)((message) => {
|
|
4306
4491
|
setMessages((prev) => [...prev, message]);
|
|
4307
4492
|
}, []);
|
|
4308
|
-
const handleSend = (0,
|
|
4493
|
+
const handleSend = (0, import_react7.useCallback)(async () => {
|
|
4309
4494
|
if (!mapId) {
|
|
4310
4495
|
setErrorMessage("Selecciona un mapa para usar el asistente.");
|
|
4311
4496
|
return;
|
|
@@ -4340,11 +4525,11 @@ var FloatingChatBox = ({
|
|
|
4340
4525
|
response
|
|
4341
4526
|
});
|
|
4342
4527
|
} catch (error) {
|
|
4343
|
-
setErrorMessage(
|
|
4528
|
+
setErrorMessage("Ocurri\xF3 un error al generar la respuesta.");
|
|
4344
4529
|
addMessage({
|
|
4345
4530
|
id: `error-${Date.now()}`,
|
|
4346
4531
|
role: "assistant",
|
|
4347
|
-
content:
|
|
4532
|
+
content: "\u274C Ocurri\xF3 un error al generar la respuesta."
|
|
4348
4533
|
});
|
|
4349
4534
|
}
|
|
4350
4535
|
}, [
|
|
@@ -4358,7 +4543,7 @@ var FloatingChatBox = ({
|
|
|
4358
4543
|
sendMessage2,
|
|
4359
4544
|
userId
|
|
4360
4545
|
]);
|
|
4361
|
-
const handleKeyDown = (0,
|
|
4546
|
+
const handleKeyDown = (0, import_react7.useCallback)(
|
|
4362
4547
|
(event) => {
|
|
4363
4548
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
4364
4549
|
event.preventDefault();
|
|
@@ -4369,20 +4554,20 @@ var FloatingChatBox = ({
|
|
|
4369
4554
|
},
|
|
4370
4555
|
[canSend, handleSend]
|
|
4371
4556
|
);
|
|
4372
|
-
const handleFollowUpClick = (0,
|
|
4557
|
+
const handleFollowUpClick = (0, import_react7.useCallback)((question) => {
|
|
4373
4558
|
setInputValue(question);
|
|
4374
4559
|
}, []);
|
|
4375
4560
|
const renderMetadata = (response) => {
|
|
4376
4561
|
if (!response?.metadata) return null;
|
|
4377
4562
|
const referencedLayers = response.metadata.referencedLayers;
|
|
4378
4563
|
if (!referencedLayers || referencedLayers.length === 0) return null;
|
|
4379
|
-
return /* @__PURE__ */ (0,
|
|
4380
|
-
/* @__PURE__ */ (0,
|
|
4381
|
-
/* @__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, {}),
|
|
4382
4567
|
"Capas Analizadas"
|
|
4383
4568
|
] }),
|
|
4384
|
-
/* @__PURE__ */ (0,
|
|
4385
|
-
/* @__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 }),
|
|
4386
4571
|
" (",
|
|
4387
4572
|
layer.featureCount,
|
|
4388
4573
|
" ",
|
|
@@ -4391,7 +4576,7 @@ var FloatingChatBox = ({
|
|
|
4391
4576
|
] }, index)) })
|
|
4392
4577
|
] });
|
|
4393
4578
|
};
|
|
4394
|
-
const handleActionClick = (0,
|
|
4579
|
+
const handleActionClick = (0, import_react7.useCallback)((action) => {
|
|
4395
4580
|
if (isStreaming) return;
|
|
4396
4581
|
setOpen(false);
|
|
4397
4582
|
requestAnimationFrame(() => {
|
|
@@ -4400,9 +4585,9 @@ var FloatingChatBox = ({
|
|
|
4400
4585
|
}, [isStreaming, setOpen, onActionClick]);
|
|
4401
4586
|
const renderActions = (response) => {
|
|
4402
4587
|
if (!response?.suggestedActions?.length) return null;
|
|
4403
|
-
return /* @__PURE__ */ (0,
|
|
4404
|
-
/* @__PURE__ */ (0,
|
|
4405
|
-
/* @__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)(
|
|
4406
4591
|
"button",
|
|
4407
4592
|
{
|
|
4408
4593
|
type: "button",
|
|
@@ -4433,9 +4618,9 @@ var FloatingChatBox = ({
|
|
|
4433
4618
|
};
|
|
4434
4619
|
const renderFollowUps = (response) => {
|
|
4435
4620
|
if (!response?.followUpQuestions?.length) return null;
|
|
4436
|
-
return /* @__PURE__ */ (0,
|
|
4437
|
-
/* @__PURE__ */ (0,
|
|
4438
|
-
/* @__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)(
|
|
4439
4624
|
"button",
|
|
4440
4625
|
{
|
|
4441
4626
|
type: "button",
|
|
@@ -4464,8 +4649,8 @@ var FloatingChatBox = ({
|
|
|
4464
4649
|
)) })
|
|
4465
4650
|
] });
|
|
4466
4651
|
};
|
|
4467
|
-
const chatContent = /* @__PURE__ */ (0,
|
|
4468
|
-
/* @__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: `
|
|
4469
4654
|
@keyframes zenitBlink {
|
|
4470
4655
|
0%, 49% { opacity: 1; }
|
|
4471
4656
|
50%, 100% { opacity: 0; }
|
|
@@ -4508,11 +4693,13 @@ var FloatingChatBox = ({
|
|
|
4508
4693
|
@media (max-width: 768px) {
|
|
4509
4694
|
.zenit-chat-panel.zenit-chat-panel--fullscreen {
|
|
4510
4695
|
position: fixed !important;
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
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;
|
|
4516
4703
|
border-radius: 0 !important;
|
|
4517
4704
|
display: flex !important;
|
|
4518
4705
|
flex-direction: column !important;
|
|
@@ -4535,7 +4722,7 @@ var FloatingChatBox = ({
|
|
|
4535
4722
|
}
|
|
4536
4723
|
}
|
|
4537
4724
|
` }),
|
|
4538
|
-
open && /* @__PURE__ */ (0,
|
|
4725
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
4539
4726
|
"div",
|
|
4540
4727
|
{
|
|
4541
4728
|
ref: chatBoxRef,
|
|
@@ -4545,10 +4732,10 @@ var FloatingChatBox = ({
|
|
|
4545
4732
|
...expanded ? styles.panelExpanded : styles.panelNormal
|
|
4546
4733
|
},
|
|
4547
4734
|
children: [
|
|
4548
|
-
/* @__PURE__ */ (0,
|
|
4549
|
-
/* @__PURE__ */ (0,
|
|
4550
|
-
/* @__PURE__ */ (0,
|
|
4551
|
-
/* @__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)(
|
|
4552
4739
|
"button",
|
|
4553
4740
|
{
|
|
4554
4741
|
type: "button",
|
|
@@ -4561,10 +4748,10 @@ var FloatingChatBox = ({
|
|
|
4561
4748
|
e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
|
|
4562
4749
|
},
|
|
4563
4750
|
"aria-label": expanded ? "Contraer" : "Expandir",
|
|
4564
|
-
children: expanded ? /* @__PURE__ */ (0,
|
|
4751
|
+
children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CollapseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ExpandIcon, {})
|
|
4565
4752
|
}
|
|
4566
4753
|
),
|
|
4567
|
-
/* @__PURE__ */ (0,
|
|
4754
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4568
4755
|
"button",
|
|
4569
4756
|
{
|
|
4570
4757
|
type: "button",
|
|
@@ -4577,20 +4764,20 @@ var FloatingChatBox = ({
|
|
|
4577
4764
|
e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
|
|
4578
4765
|
},
|
|
4579
4766
|
"aria-label": "Cerrar",
|
|
4580
|
-
children: /* @__PURE__ */ (0,
|
|
4767
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {})
|
|
4581
4768
|
}
|
|
4582
4769
|
)
|
|
4583
4770
|
] })
|
|
4584
4771
|
] }),
|
|
4585
|
-
/* @__PURE__ */ (0,
|
|
4586
|
-
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)(
|
|
4587
4774
|
"div",
|
|
4588
4775
|
{
|
|
4589
4776
|
style: {
|
|
4590
4777
|
...styles.messageWrapper,
|
|
4591
4778
|
alignItems: message.role === "user" ? "flex-end" : "flex-start"
|
|
4592
4779
|
},
|
|
4593
|
-
children: /* @__PURE__ */ (0,
|
|
4780
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
4594
4781
|
"div",
|
|
4595
4782
|
{
|
|
4596
4783
|
style: {
|
|
@@ -4598,7 +4785,7 @@ var FloatingChatBox = ({
|
|
|
4598
4785
|
...message.role === "user" ? styles.userMessage : styles.assistantMessage
|
|
4599
4786
|
},
|
|
4600
4787
|
children: [
|
|
4601
|
-
message.role === "assistant" ? /* @__PURE__ */ (0,
|
|
4788
|
+
message.role === "assistant" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MarkdownRenderer, { content: message.content }) : message.content,
|
|
4602
4789
|
message.role === "assistant" && renderMetadata(message.response),
|
|
4603
4790
|
message.role === "assistant" && renderActions(message.response),
|
|
4604
4791
|
message.role === "assistant" && renderFollowUps(message.response)
|
|
@@ -4608,39 +4795,39 @@ var FloatingChatBox = ({
|
|
|
4608
4795
|
},
|
|
4609
4796
|
message.id
|
|
4610
4797
|
)),
|
|
4611
|
-
isStreaming && /* @__PURE__ */ (0,
|
|
4798
|
+
isStreaming && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4612
4799
|
"div",
|
|
4613
4800
|
{
|
|
4614
4801
|
style: {
|
|
4615
4802
|
...styles.messageWrapper,
|
|
4616
4803
|
alignItems: "flex-start"
|
|
4617
4804
|
},
|
|
4618
|
-
children: /* @__PURE__ */ (0,
|
|
4805
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4619
4806
|
"div",
|
|
4620
4807
|
{
|
|
4621
4808
|
style: {
|
|
4622
4809
|
...styles.messageBubble,
|
|
4623
4810
|
...styles.assistantMessage
|
|
4624
4811
|
},
|
|
4625
|
-
children: streamingText ? /* @__PURE__ */ (0,
|
|
4626
|
-
/* @__PURE__ */ (0,
|
|
4627
|
-
/* @__PURE__ */ (0,
|
|
4628
|
-
] }) : /* @__PURE__ */ (0,
|
|
4629
|
-
/* @__PURE__ */ (0,
|
|
4630
|
-
/* @__PURE__ */ (0,
|
|
4631
|
-
/* @__PURE__ */ (0,
|
|
4632
|
-
/* @__PURE__ */ (0,
|
|
4633
|
-
/* @__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 })
|
|
4634
4821
|
] })
|
|
4635
4822
|
] })
|
|
4636
4823
|
}
|
|
4637
4824
|
)
|
|
4638
4825
|
}
|
|
4639
4826
|
),
|
|
4640
|
-
/* @__PURE__ */ (0,
|
|
4827
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: messagesEndRef })
|
|
4641
4828
|
] }),
|
|
4642
|
-
/* @__PURE__ */ (0,
|
|
4643
|
-
/* @__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)(
|
|
4644
4831
|
"textarea",
|
|
4645
4832
|
{
|
|
4646
4833
|
style: {
|
|
@@ -4657,7 +4844,7 @@ var FloatingChatBox = ({
|
|
|
4657
4844
|
disabled: !mapId || !baseUrl || isStreaming
|
|
4658
4845
|
}
|
|
4659
4846
|
),
|
|
4660
|
-
/* @__PURE__ */ (0,
|
|
4847
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4661
4848
|
"button",
|
|
4662
4849
|
{
|
|
4663
4850
|
type: "button",
|
|
@@ -4666,36 +4853,38 @@ var FloatingChatBox = ({
|
|
|
4666
4853
|
onClick: () => void handleSend(),
|
|
4667
4854
|
disabled: !canSend,
|
|
4668
4855
|
"aria-label": "Enviar mensaje",
|
|
4669
|
-
children: /* @__PURE__ */ (0,
|
|
4856
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SendIcon, {})
|
|
4670
4857
|
}
|
|
4671
4858
|
)
|
|
4672
4859
|
] }),
|
|
4673
|
-
errorMessage && /* @__PURE__ */ (0,
|
|
4674
|
-
|
|
4675
|
-
!
|
|
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" })
|
|
4676
4864
|
]
|
|
4677
4865
|
}
|
|
4678
4866
|
),
|
|
4679
|
-
!(hideButton && !open) && /* @__PURE__ */ (0,
|
|
4867
|
+
!(hideButton && !open) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4680
4868
|
"button",
|
|
4681
4869
|
{
|
|
4682
4870
|
type: "button",
|
|
4683
4871
|
className: `zenit-ai-button ${open ? "open" : ""}${open && isMobile ? " zenit-ai-button--hidden-mobile" : ""}`,
|
|
4684
4872
|
style: {
|
|
4685
4873
|
...styles.floatingButton,
|
|
4686
|
-
...open ? styles.floatingButtonOpen : isMobile ? styles.floatingButtonMobile : styles.floatingButtonClosed
|
|
4874
|
+
...open ? styles.floatingButtonOpen : isMobile ? styles.floatingButtonMobile : styles.floatingButtonClosed,
|
|
4875
|
+
zIndex: open ? 100001 : 99999
|
|
4687
4876
|
},
|
|
4688
4877
|
onClick: () => setOpen((prev) => !prev),
|
|
4689
4878
|
"aria-label": open ? "Cerrar asistente" : "Abrir asistente Zenit AI",
|
|
4690
|
-
children: open ? /* @__PURE__ */ (0,
|
|
4691
|
-
/* @__PURE__ */ (0,
|
|
4692
|
-
!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" })
|
|
4693
4882
|
] })
|
|
4694
4883
|
}
|
|
4695
4884
|
)
|
|
4696
4885
|
] });
|
|
4697
4886
|
if (typeof document !== "undefined") {
|
|
4698
|
-
return (0,
|
|
4887
|
+
return (0, import_react_dom2.createPortal)(chatContent, document.body);
|
|
4699
4888
|
}
|
|
4700
4889
|
return chatContent;
|
|
4701
4890
|
};
|
|
@@ -4746,12 +4935,15 @@ var FloatingChatBox = ({
|
|
|
4746
4935
|
getZoomOpacityFactor,
|
|
4747
4936
|
initLayerStates,
|
|
4748
4937
|
isPolygonLayer,
|
|
4938
|
+
mergeFilters,
|
|
4749
4939
|
normalizeBbox,
|
|
4940
|
+
normalizeFilters,
|
|
4750
4941
|
normalizeMapCenter,
|
|
4751
4942
|
normalizeMapLayers,
|
|
4752
4943
|
resetOverrides,
|
|
4753
4944
|
resolveLayerAccent,
|
|
4754
4945
|
resolveLayerStrategy,
|
|
4946
|
+
resolveRuntimeConfig,
|
|
4755
4947
|
sendMessage,
|
|
4756
4948
|
sendMessageStream,
|
|
4757
4949
|
shouldSkipGeojsonDownload,
|