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/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 import_react = __toESM(require("react"));
1407
- var import_react_leaflet = require("react-leaflet");
1408
- var import_leaflet = __toESM(require("leaflet"));
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: 10,
1431
- maxZoom: 17,
1432
- minFactor: 0.6,
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/ZenitMap.tsx
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 DEFAULT_CENTER = [0, 0];
1472
- var DEFAULT_ZOOM = 3;
1473
- var LABELS_PANE_NAME = "zenit-labels-pane";
1474
- function computeBBoxFromGeojson(geojson) {
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 isGeoJsonFeatureCollection(value) {
1518
- if (!isRecord(value)) return false;
1519
- const features = value.features;
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 extractGeoJsonFeatureCollection(value) {
1525
- if (isRecord(value) && "data" in value) {
1526
- const data = value.data;
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 getFeatureLayerId(feature) {
1532
- const layerId = feature?.properties?.__zenit_layerId ?? feature?.properties?.layerId ?? feature?.properties?.layer_id;
1533
- if (layerId === void 0 || layerId === null) return null;
1534
- return layerId;
1604
+ function buildFeatureCollection(features) {
1605
+ return {
1606
+ type: "FeatureCollection",
1607
+ features
1608
+ };
1535
1609
  }
1536
- function escapeHtml(value) {
1537
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
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
- var DESCRIPTION_KEYS = /* @__PURE__ */ new Set(["descripcion", "description"]);
1540
- var POPUP_EXCLUDED_KEYS = /* @__PURE__ */ new Set(["geom", "geometry"]);
1541
- var POPUP_HEADER_KEYS = ["nombre", "name", "title", "titulo"];
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 DESKTOP_POPUP_DIMENSIONS = { maxWidth: 350, minWidth: 280, maxHeight: 480 };
1544
- var MOBILE_POPUP_DIMENSIONS = { maxWidth: 280, minWidth: 240, maxHeight: 380 };
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
- /* ===== Zenit Leaflet Popup - Modern Professional Styling ===== */
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
- overflow: hidden;
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
- /* Content area with scroll support */
1561
- .zenit-leaflet-popup .leaflet-popup-content {
1745
+ .custom-leaflet-popup .leaflet-popup-content {
1562
1746
  margin: 0;
1563
- padding: 0;
1747
+ padding: 12px 14px;
1564
1748
  font-size: 13px;
1565
- line-height: 1.5;
1566
- color: #374151;
1567
- min-width: 100%;
1568
- max-height: min(70vh, 480px);
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(156, 163, 175, 0.5) transparent;
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
- /* Close button styling */
1586
- .zenit-leaflet-popup .leaflet-popup-close-button {
1587
- color: #9ca3af;
1588
- font-size: 18px;
1589
- font-weight: 400;
1590
- width: 28px;
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
- .zenit-popup-title {
1626
- font-size: 14px;
1627
- font-weight: 700;
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
- /* Individual row styling with subtle separator */
1634
- .zenit-popup-row {
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
- .zenit-popup-row:first-child {
1643
- padding-top: 0;
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
- .zenit-popup-row:last-child {
1647
- border-bottom: none;
1648
- padding-bottom: 0;
1779
+ .custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-track {
1780
+ background: transparent;
1649
1781
  }
1650
1782
 
1651
- /* Label styling - small, gray, uppercase */
1652
- .zenit-popup-label {
1653
- font-size: 10px;
1654
- font-weight: 500;
1655
- color: #9ca3af;
1656
- text-transform: uppercase;
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
- /* Value styling - darker, readable */
1662
- .zenit-popup-value {
1663
- font-size: 13px;
1664
- font-weight: 400;
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-popup-link {
1672
- color: #2563eb;
1673
- text-decoration: underline;
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-popup-link:hover {
1678
- color: #1d4ed8;
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
- /* Preformatted text (JSON objects) */
1704
- .zenit-popup-pre {
1705
- margin: 0;
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
- border: 1px solid #e5e7eb;
1715
- }
1716
-
1717
- /* Empty state styling */
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
- /* Webkit scrollbar styling */
1727
- .zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar {
1728
- width: 6px;
1820
+ `;
1821
+ function clampNumber2(value, min, max) {
1822
+ return Math.min(max, Math.max(min, value));
1729
1823
  }
1730
-
1731
- .zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-track {
1732
- background: transparent;
1824
+ function clampOpacity4(value) {
1825
+ return clampNumber2(value, 0, 1);
1733
1826
  }
1734
-
1735
- .zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb {
1736
- background-color: rgba(156, 163, 175, 0.4);
1737
- border-radius: 3px;
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
- .zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb:hover {
1741
- background-color: rgba(107, 114, 128, 0.6);
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
- /* Scrollbar for description field */
1745
- .zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar {
1746
- width: 4px;
1845
+ function escapeHtml(value) {
1846
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
1747
1847
  }
1748
-
1749
- .zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar-track {
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
- .zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar-thumb {
1754
- background-color: rgba(156, 163, 175, 0.4);
1755
- border-radius: 2px;
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
- .zenit-leaflet-popup .leaflet-popup-close-button {
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
- .zenit-popup-card {
1772
- padding: 12px;
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
- .zenit-leaflet-popup .leaflet-popup-content {
1776
- max-height: min(65vh, 380px);
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
- .zenit-popup-header {
1780
- padding-bottom: 10px;
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
- .zenit-popup-title {
1784
- font-size: 13px;
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
- .zenit-popup-row {
1788
- padding: 8px 0;
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
- .zenit-popup-label {
1792
- font-size: 9px;
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
- .zenit-popup-value {
1796
- font-size: 12px;
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
- .zenit-popup-row.zenit-popup-description {
1800
- margin: 0 -12px;
1801
- padding: 10px 12px;
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
- .zenit-popup-row.zenit-popup-description .zenit-popup-value {
1805
- font-size: 12px;
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
- .zenit-popup-pre {
1810
- font-size: 10px;
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
- .zenit-popup-empty {
1815
- font-size: 12px;
1816
- padding: 16px 0;
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
- /* ===== Map tooltip styling ===== */
1821
- .zenit-map-tooltip {
1822
- background-color: rgba(31, 41, 55, 0.95);
2075
+ .zenit-location-button {
2076
+ width: 42px;
2077
+ height: 42px;
2078
+ border-radius: 12px;
1823
2079
  border: none;
1824
- border-radius: 6px;
1825
- color: #ffffff;
1826
- font-size: 12px;
1827
- font-weight: 500;
1828
- padding: 6px 10px;
1829
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
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-map-tooltip::before {
1833
- border-top-color: rgba(31, 41, 55, 0.95);
2090
+ .zenit-location-button.zenit-location-button--tracking {
2091
+ animation: zenitLocationPulse 1.8s infinite;
1834
2092
  }
1835
2093
 
1836
- .polygon-label-tooltip {
1837
- z-index: 600 !important;
2094
+ .zenit-location-button:hover {
2095
+ background: #f8fafc;
1838
2096
  }
1839
2097
 
1840
- .zenit-map-shell.popup-open .zenit-label-marker,
1841
- .zenit-map-shell.popup-open .polygon-label-tooltip,
1842
- .zenit-map-shell.popup-open .click-for-detail-hint,
1843
- .zenit-map-shell.popup-open .zenit-map-tooltip {
1844
- display: none !important;
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
- function ensurePopupStyles() {
1848
- if (typeof document === "undefined") return;
1849
- if (document.getElementById(POPUP_STYLE_ID)) return;
1850
- const styleTag = document.createElement("style");
1851
- styleTag.id = POPUP_STYLE_ID;
1852
- styleTag.textContent = ZENIT_LEAFLET_POPUP_STYLES;
1853
- document.head.appendChild(styleTag);
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
- function getPopupDimensions() {
1856
- if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
1857
- return DESKTOP_POPUP_DIMENSIONS;
1858
- }
1859
- return window.matchMedia("(max-width: 640px)").matches ? MOBILE_POPUP_DIMENSIONS : DESKTOP_POPUP_DIMENSIONS;
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
- function normalizeDescriptionValue(value) {
1862
- if (value === void 0 || value === null) return null;
1863
- if (typeof value === "string") {
1864
- const trimmed = value.trim();
1865
- return trimmed ? trimmed : null;
1866
- }
1867
- if (typeof value === "number" || typeof value === "boolean") {
1868
- return String(value);
1869
- }
1870
- return null;
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 extractDescriptionValue(properties) {
1873
- if (!properties) return null;
1874
- const matches = Object.entries(properties).find(
1875
- ([key]) => DESCRIPTION_KEYS.has(key.toLowerCase())
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
- function safeJsonStringify(value) {
1881
- try {
1882
- const json = JSON.stringify(value, null, 2);
1883
- if (json !== void 0) return json;
1884
- } catch {
1885
- }
1886
- return String(value);
1887
- }
1888
- function renderPopupValue(value) {
1889
- if (value === null || value === void 0) {
1890
- return '<span class="zenit-popup-empty">Sin datos</span>';
1891
- }
1892
- if (value instanceof Date) {
1893
- return `<span>${escapeHtml(value.toLocaleDateString("es-GT"))}</span>`;
1894
- }
1895
- if (typeof value === "number") {
1896
- return `<span>${escapeHtml(value.toLocaleString("es-GT"))}</span>`;
1897
- }
1898
- if (typeof value === "string") {
1899
- const trimmed = value.trim();
1900
- const isLikelyDate = /^\d{4}-\d{2}-\d{2}/.test(trimmed) || trimmed.includes("T");
1901
- if (isLikelyDate) {
1902
- const parsed = Date.parse(trimmed);
1903
- if (!Number.isNaN(parsed)) {
1904
- return `<span>${escapeHtml(new Date(parsed).toLocaleDateString("es-GT"))}</span>`;
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
- try {
1908
- const parsedUrl = new URL(trimmed);
1909
- if (parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:") {
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
- return `<span>${escapeHtml(trimmed || value)}</span>`;
1916
- }
1917
- if (typeof value === "object") {
1918
- const json = safeJsonStringify(value);
1919
- return `<pre class="zenit-popup-pre">${escapeHtml(json)}</pre>`;
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
- if (!entry) return null;
1946
- return entry[1].trim();
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 formatLabel(key) {
1949
- return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").trim();
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 createPopupContent(properties) {
1952
- const headerText = extractPopupHeader(properties);
1953
- const entries = Object.entries(properties).filter(([key, value]) => {
1954
- if (!shouldIncludePopupEntry(key, value)) return false;
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
- rowsHtml += otherEntries.map(([key, value]) => {
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 withAlpha(color, alpha) {
1993
- const trimmed = color.trim();
1994
- if (trimmed.startsWith("#")) {
1995
- const hex = trimmed.replace("#", "");
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
- function getRgbFromColor(color) {
2015
- const trimmed = color.trim();
2016
- if (trimmed.startsWith("#")) {
2017
- const hex = trimmed.replace("#", "");
2018
- const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
2019
- if (expanded.length === 6) {
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
- const rgbMatch = trimmed.match(/rgba?\(([^)]+)\)/i);
2027
- if (rgbMatch) {
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 getLabelTextStyles(color) {
2036
- const rgb = getRgbFromColor(color);
2037
- if (!rgb) {
2038
- return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.6)" };
2039
- }
2040
- const luminance = (0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b) / 255;
2041
- if (luminance > 0.6) {
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 FitToBounds = ({ bbox }) => {
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, import_react.useState)(null);
2208
- const [layers, setLayers] = (0, import_react.useState)([]);
2209
- const [effectiveStates, setEffectiveStates] = (0, import_react.useState)([]);
2210
- const [loadingMap, setLoadingMap] = (0, import_react.useState)(false);
2211
- const [mapError, setMapError] = (0, import_react.useState)(null);
2212
- const [mapInstance, setMapInstance] = (0, import_react.useState)(null);
2213
- const [panesReady, setPanesReady] = (0, import_react.useState)(false);
2214
- const [currentZoom, setCurrentZoom] = (0, import_react.useState)(initialZoom ?? DEFAULT_ZOOM);
2215
- const [isPopupOpen, setIsPopupOpen] = (0, import_react.useState)(false);
2216
- const [isMobile, setIsMobile] = (0, import_react.useState)(() => {
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, import_react.useMemo)(() => normalizeMapLayers(map), [map]);
2221
- (0, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
2468
+ (0, import_react4.useEffect)(() => {
2240
2469
  if (featureInfoMode === "popup") {
2241
2470
  ensurePopupStyles();
2242
2471
  }
2243
2472
  }, [featureInfoMode]);
2244
- (0, import_react.useEffect)(() => {
2473
+ (0, import_react4.useEffect)(() => {
2245
2474
  if (featureInfoMode !== "popup") {
2246
2475
  setIsPopupOpen(false);
2247
2476
  }
2248
2477
  }, [featureInfoMode]);
2249
- (0, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
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, import_react.useMemo)(() => {
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, import_react.useMemo)(() => {
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, import_react.useMemo)(() => {
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, import_react.useMemo)(() => {
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 [baseStates, setBaseStates] = (0, import_react.useState)([]);
2320
- const [mapOverrides, setMapOverrides] = (0, import_react.useState)([]);
2321
- const [controlOverrides, setControlOverrides] = (0, import_react.useState)([]);
2322
- const [uiOverrides, setUiOverrides] = (0, import_react.useState)([]);
2323
- (0, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
2632
+ (0, import_react4.useEffect)(() => {
2400
2633
  if (layerStates) {
2401
2634
  setEffectiveStates(layerStates);
2402
2635
  }
2403
2636
  }, [layerStates]);
2404
- (0, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
2650
+ (0, import_react4.useEffect)(() => {
2418
2651
  if (!Array.isArray(layerControls) || layerControls.length > 0) return;
2419
2652
  setUiOverrides([]);
2420
2653
  }, [layerControls]);
2421
- (0, import_react.useEffect)(() => {
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, import_react.useCallback)(
2674
+ const updateOpacityFromUi = (0, import_react4.useCallback)(
2442
2675
  (layerId, uiOpacity) => {
2443
2676
  const meta = layerMetaIndex.get(String(layerId));
2444
- const zoomFactor = getLayerZoomOpacityFactor(
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, import_react.useMemo)(() => {
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, import_react.useEffect)(() => {
2724
+ (0, import_react4.useEffect)(() => {
2497
2725
  setCurrentZoom(zoom);
2498
2726
  }, [zoom]);
2499
- const decoratedLayers = (0, import_react.useMemo)(() => {
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, import_react.useMemo)(() => {
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 explicitZoomBBox = (0, import_react.useMemo)(() => {
2510
- if (zoomToBbox) return zoomToBbox;
2511
- if (zoomToGeojson) return computeBBoxFromGeojson(zoomToGeojson);
2512
- return null;
2513
- }, [zoomToBbox, zoomToGeojson]);
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, import_react.useMemo)(() => {
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 opacity = layerState.effective?.opacity ?? 1;
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, import_react.useCallback)(
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, import_react.useCallback)(
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, import_react.useEffect)(() => {
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, import_react.useMemo)(() => {
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 import_leaflet.default.CircleMarker;
2604
- const originalStyle = layer instanceof import_leaflet.default.Path ? {
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 import_leaflet.default.CircleMarker ? layer.getRadius() : null;
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: "zenit-leaflet-popup custom-leaflet-popup",
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 import_leaflet.default.Path && originalStyle) {
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 import_leaflet.default.CircleMarker && typeof originalRadius === "number") {
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 import_leaflet.default.Path && originalStyle) {
2911
+ if (layer instanceof import_leaflet4.default.Path && originalStyle) {
2684
2912
  layer.setStyle(originalStyle);
2685
2913
  }
2686
- if (layer instanceof import_leaflet.default.CircleMarker && typeof originalRadius === "number") {
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
- const sanitizedBaseOpacity = clampOpacity3(baseOpacity);
2699
- const normalizedStyleFill = typeof resolvedStyle?.fillOpacity === "number" ? clampOpacity3(resolvedStyle.fillOpacity) : 0.8;
2700
- const effectiveOpacity = getEffectiveLayerOpacity(
2701
- sanitizedBaseOpacity,
2702
- currentZoom,
2703
- resolvedLayerType,
2704
- geometryType
2705
- );
2706
- const fillOpacity = clampOpacity3(effectiveOpacity * normalizedStyleFill);
2707
- const strokeOpacity = clampOpacity3(Math.max(0.35, effectiveOpacity * 0.9));
2708
- return {
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
- const buildLabelIcon = (0, import_react.useCallback)((label, opacity, color) => {
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, import_jsx_runtime.jsx)("div", { style: { padding: 16, height, width }, children: "Cargando mapa..." });
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, import_jsx_runtime.jsxs)("div", { style: { padding: 16, height, width, color: "red" }, children: [
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, import_jsx_runtime.jsxs)(
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, import_jsx_runtime.jsx)(
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, import_jsx_runtime.jsxs)(
2855
- import_react_leaflet.MapContainer,
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, import_jsx_runtime.jsx)(
2864
- import_react_leaflet.TileLayer,
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, import_jsx_runtime.jsx)(import_react_leaflet.ZoomControl, { position: "topright" }),
2871
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MapInstanceBridge, { onReady: handleMapReady }),
2872
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FitToBounds, { bbox: explicitZoomBBox ?? void 0 }),
2873
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AutoFitToBounds, { bbox: autoZoomBBox ?? void 0, enabled: !explicitZoomBBox }),
2874
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ZoomBasedOpacityHandler, { onZoomChange: handleZoomChange }),
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 data = layerState.data?.features ?? [];
2881
- const fillFeatures = data.filter(isNonPointGeometry);
2882
- const pointFeatures = data.filter(isPointGeometry);
2883
- const fillData = fillFeatures.length > 0 ? buildFeatureCollection(fillFeatures) : null;
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
- data: pointsData,
2899
- pane: panesReady && mapInstance?.getPane(pointsPaneName) ? pointsPaneName : void 0,
2900
- pointToLayer: (feature, latlng) => import_leaflet.default.circleMarker(latlng, {
2901
- radius: isMobile ? 8 : 6,
2902
- ...buildLayerStyle(layerState.mapLayer.layerId, baseOpacity, feature, layerType)
2903
- }),
2904
- onEachFeature: overlayOnEachFeature
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, import_jsx_runtime.jsx)(
2910
- import_react_leaflet.Marker,
3088
+ ).map((marker) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3089
+ import_react_leaflet4.Marker,
2911
3090
  {
2912
3091
  position: marker.position,
2913
- icon: buildLabelIcon(marker.label, marker.opacity, marker.color),
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, import_jsx_runtime.jsx)(
2922
- import_react_leaflet.GeoJSON,
3100
+ overlayGeojson && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3101
+ LayerGeoJson,
2923
3102
  {
3103
+ layerId: "overlay-geojson",
2924
3104
  data: overlayGeojson,
2925
- style: overlayStyleFunction,
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, import_jsx_runtime.jsxs)(
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, import_jsx_runtime.jsxs)(
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, import_jsx_runtime.jsx)("div", { style: { fontWeight: 600, marginBottom: 4 }, children: "Overlay activo" }),
2962
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 13 }, children: [
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, import_jsx_runtime.jsx)("div", { style: { fontWeight: 600, marginBottom: 12 }, children: "Capas" }),
2971
- decoratedLayers.map((layerState) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
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, import_jsx_runtime.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
2977
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
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, import_jsx_runtime.jsx)("span", { children: layerState.layer?.name ?? `Capa ${layerState.mapLayer.layerId}` })
3173
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: layerState.layer?.name ?? `Capa ${layerState.mapLayer.layerId}` })
2989
3174
  ] }),
2990
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: 8 }, children: [
2991
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 4 }, children: [
2992
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "#4a5568" }, children: "Opacidad" }),
2993
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
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, import_jsx_runtime.jsx)(
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 import_react2 = __toESM(require("react"));
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 import_jsx_runtime2 = require("react/jsx-runtime");
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, import_react2.useState)(null);
3075
- const [loadingMap, setLoadingMap] = (0, import_react2.useState)(false);
3076
- const [mapError, setMapError] = (0, import_react2.useState)(null);
3077
- const [layers, setLayers] = (0, import_react2.useState)([]);
3078
- const [activeTab, setActiveTab] = (0, import_react2.useState)("layers");
3079
- const [panelVisible, setPanelVisible] = (0, import_react2.useState)(true);
3080
- const lastEmittedStatesRef = (0, import_react2.useRef)(null);
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, import_react2.useMemo)(
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, import_react2.useMemo)(
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, import_react2.useMemo)(
3288
+ const effectiveStates = (0, import_react5.useMemo)(
3104
3289
  () => layerStates ?? applyLayerOverrides(baseStates, overrideStates),
3105
3290
  [baseStates, layerStates, overrideStates]
3106
3291
  );
3107
- const layerMetaIndex = (0, import_react2.useMemo)(() => {
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 = import_react2.default.useCallback((state) => {
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 = import_react2.default.useCallback(
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, import_react2.useMemo)(() => {
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, import_react2.useEffect)(() => {
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, import_react2.useEffect)(() => {
3376
+ (0, import_react5.useEffect)(() => {
3192
3377
  if (!showUploadTab && activeTab === "upload") {
3193
3378
  setActiveTab("layers");
3194
3379
  }
3195
3380
  }, [activeTab, showUploadTab]);
3196
- (0, import_react2.useEffect)(() => {
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 = import_react2.default.useCallback(
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 = import_react2.default.useCallback(
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 = import_react2.default.useCallback(
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, import_react2.useMemo)(() => {
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 = import_react2.default.useCallback(
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, import_jsx_runtime2.jsx)("div", { className, style: panelStyle, children: "Cargando capas\u2026" });
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, import_jsx_runtime2.jsxs)("div", { className, style: { ...panelStyle, color: "#c53030" }, children: [
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, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: decoratedLayers.map((layerState) => {
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, import_jsx_runtime2.jsxs)(
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, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
3350
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: 10, alignItems: "flex-start", minWidth: 0, flex: 1 }, children: [
3351
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
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, import_jsx_runtime2.jsx)(
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, import_jsx_runtime2.jsx)(import_lucide_react.Eye, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.EyeOff, { size: 16 })
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, import_jsx_runtime2.jsxs)("div", { style: { minWidth: 0, flex: 1 }, children: [
3381
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
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, import_jsx_runtime2.jsxs)("div", { style: { color: muted ? "#94a3b8" : "#64748b", fontSize: 12 }, children: [
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, import_jsx_runtime2.jsx)("div", { style: { display: "flex", alignItems: "flex-start", gap: 6, flexShrink: 0 }, children: typeof featureCount === "number" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "zlm-badge", children: [
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, import_jsx_runtime2.jsx)("div", { style: { display: "flex", gap: 10, alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { flex: 1 }, children: [
3411
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 6, color: "#64748b", fontSize: 12 }, children: [
3412
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Opacidad" }),
3413
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
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, import_jsx_runtime2.jsx)(
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, import_jsx_runtime2.jsxs)("div", { className: ["zenit-layer-manager", className].filter(Boolean).join(" "), style: panelStyle, children: [
3457
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: `
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, import_jsx_runtime2.jsxs)("div", { style: headerStyle, children: [
3553
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
3554
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
3555
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontWeight: 800, fontSize: 16, color: "#0f172a" }, children: "Gesti\xF3n de Capas" }),
3556
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { color: "#64748b", fontSize: 12 }, children: [
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, import_jsx_runtime2.jsxs)(
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, import_jsx_runtime2.jsx)(import_lucide_react.Eye, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.EyeOff, { size: 16 }),
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, import_jsx_runtime2.jsxs)(
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, import_jsx_runtime2.jsxs)(
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, import_jsx_runtime2.jsx)(import_lucide_react.Layers, { size: 16 }),
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, import_jsx_runtime2.jsxs)(
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, import_jsx_runtime2.jsx)(import_lucide_react.Upload, { size: 16 }),
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, import_jsx_runtime2.jsxs)("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
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, import_jsx_runtime2.jsx)("div", { style: { color: "#475569", fontSize: 13 }, children: "Pr\xF3ximamente podr\xE1s subir capas desde este panel." })
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 import_jsx_runtime3 = require("react/jsx-runtime");
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, import_jsx_runtime3.jsxs)(
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, import_jsx_runtime3.jsxs)("header", { style: { marginBottom: 12 }, children: [
3646
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { style: { margin: 0, fontSize: 16 }, children: title }),
3647
- description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: { margin: "6px 0 0", color: "#475569", fontSize: 13 }, children: description })
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, import_jsx_runtime3.jsx)("div", { children })
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 import_react4 = require("react");
3657
- var import_react_dom = require("react-dom");
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 import_react3 = require("react");
3845
+ var import_react6 = require("react");
3661
3846
  var useSendMessage = (config) => {
3662
- const [isLoading, setIsLoading] = (0, import_react3.useState)(false);
3663
- const [error, setError] = (0, import_react3.useState)(null);
3664
- const send = (0, import_react3.useCallback)(
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, import_react3.useState)(false);
3683
- const [streamingText, setStreamingText] = (0, import_react3.useState)("");
3684
- const [completeResponse, setCompleteResponse] = (0, import_react3.useState)(null);
3685
- const [error, setError] = (0, import_react3.useState)(null);
3686
- const requestIdRef = (0, import_react3.useRef)(0);
3687
- const reset = (0, import_react3.useCallback)(() => {
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, import_react3.useCallback)(
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 import_jsx_runtime4 = require("react/jsx-runtime");
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, import_jsx_runtime4.jsx)("div", { className, style: { wordBreak: "break-word" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)("h1", { style: { fontSize: "1.5em", fontWeight: 700, marginTop: "1em", marginBottom: "0.5em" }, ...props, children }),
3770
- h2: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { style: { fontSize: "1.3em", fontWeight: 700, marginTop: "0.9em", marginBottom: "0.45em" }, ...props, children }),
3771
- h3: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { style: { fontSize: "1.15em", fontWeight: 600, marginTop: "0.75em", marginBottom: "0.4em" }, ...props, children }),
3772
- h4: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h4", { style: { fontSize: "1.05em", fontWeight: 600, marginTop: "0.6em", marginBottom: "0.35em" }, ...props, children }),
3773
- h5: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h5", { style: { fontSize: "1em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
3774
- h6: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h6", { style: { fontSize: "0.95em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
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, import_jsx_runtime4.jsx)("p", { style: { marginTop: "0.5em", marginBottom: "0.5em", lineHeight: 1.6 }, ...props, children }),
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, import_jsx_runtime4.jsx)("ul", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
3779
- ol: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ol", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
3780
- li: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { style: { marginTop: "0.25em", marginBottom: "0.25em" }, ...props, children }),
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, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)("pre", { style: { margin: 0 }, ...props, children }),
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, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)("strong", { style: { fontWeight: 600 }, ...props, children }),
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, import_jsx_runtime4.jsx)("em", { style: { fontStyle: "italic" }, ...props, children }),
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, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)("div", { style: { overflowX: "auto", marginTop: "0.5em", marginBottom: "0.5em" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)(
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 import_jsx_runtime5 = require("react/jsx-runtime");
3899
- var ChatIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.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" }) });
3900
- var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3901
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
3902
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
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, import_jsx_runtime5.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3905
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "15 3 21 3 21 9" }),
3906
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "9 21 3 21 3 15" }),
3907
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
3908
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
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, import_jsx_runtime5.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3911
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "4 14 10 14 10 20" }),
3912
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "20 10 14 10 14 4" }),
3913
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
3914
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
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, import_jsx_runtime5.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3917
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
3918
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
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, import_jsx_runtime5.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3921
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
3922
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "2 17 12 22 22 17" }),
3923
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "2 12 12 17 22 12" })
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: 24,
3933
- right: 24,
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: 15,
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: "14px 24px",
4134
+ padding: "12px 20px",
3950
4135
  gap: 8
3951
4136
  },
3952
4137
  floatingButtonOpen: {
3953
- width: 56,
3954
- height: 56,
4138
+ width: 52,
4139
+ height: 52,
3955
4140
  padding: 0
3956
4141
  },
3957
4142
  floatingButtonMobile: {
3958
- width: 56,
3959
- height: 56,
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: 92,
3966
- right: 24,
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: 400,
3978
- height: 550
4162
+ width: 360,
4163
+ height: 520
3979
4164
  },
3980
4165
  panelExpanded: {
3981
- width: 520,
3982
- height: 700
4166
+ width: 480,
4167
+ height: 640
3983
4168
  },
3984
4169
  // Header with green gradient
3985
4170
  header: {
3986
- padding: "16px 18px",
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: 16,
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: 32,
4009
- height: 32,
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: "20px 18px",
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 14px",
4220
+ padding: "10px 12px",
4036
4221
  borderRadius: 16,
4037
4222
  lineHeight: 1.5,
4038
- fontSize: 14,
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 16px",
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 12px",
4164
- fontSize: 14,
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: "10px 14px",
4361
+ padding: "8px 12px",
4177
4362
  background: "linear-gradient(135deg, #10b981, #059669)",
4178
4363
  color: "#fff",
4179
4364
  cursor: "pointer",
4180
- fontSize: 14,
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: 44,
4187
- height: 44
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, import_react4.useState)(false);
4402
+ const [internalOpen, setInternalOpen] = (0, import_react7.useState)(false);
4218
4403
  const open = isControlled ? openProp : internalOpen;
4219
- const setOpen = (0, import_react4.useCallback)((value) => {
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, import_react4.useState)(false);
4227
- const [messages, setMessages] = (0, import_react4.useState)([]);
4228
- const [inputValue, setInputValue] = (0, import_react4.useState)("");
4229
- const [conversationId, setConversationId] = (0, import_react4.useState)();
4230
- const [errorMessage, setErrorMessage] = (0, import_react4.useState)(null);
4231
- const [isFocused, setIsFocused] = (0, import_react4.useState)(false);
4232
- const [isMobile, setIsMobile] = (0, import_react4.useState)(false);
4233
- const messagesEndRef = (0, import_react4.useRef)(null);
4234
- const messagesContainerRef = (0, import_react4.useRef)(null);
4235
- const chatBoxRef = (0, import_react4.useRef)(null);
4236
- const chatConfig = (0, import_react4.useMemo)(() => {
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, import_react4.useEffect)(() => {
4427
+ (0, import_react7.useEffect)(() => {
4243
4428
  if (open && isMobile) {
4244
4429
  setExpanded(true);
4245
4430
  }
4246
4431
  }, [open, isMobile]);
4247
- const scrollToBottom = (0, import_react4.useCallback)(() => {
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, import_react4.useEffect)(() => {
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, import_react4.useEffect)(() => {
4448
+ (0, import_react7.useEffect)(() => {
4264
4449
  scrollToBottom();
4265
4450
  }, [messages, streamingText, scrollToBottom]);
4266
- (0, import_react4.useEffect)(() => {
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, import_react4.useEffect)(() => {
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, import_react4.useEffect)(() => {
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, import_react4.useCallback)((message) => {
4490
+ const addMessage = (0, import_react7.useCallback)((message) => {
4306
4491
  setMessages((prev) => [...prev, message]);
4307
4492
  }, []);
4308
- const handleSend = (0, import_react4.useCallback)(async () => {
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(error instanceof Error ? error.message : "Ocurri\xF3 un error inesperado.");
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: `\u274C Error: ${error instanceof Error ? error.message : "Ocurri\xF3 un error inesperado."}`
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, import_react4.useCallback)(
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, import_react4.useCallback)((question) => {
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, import_jsx_runtime5.jsxs)("div", { style: styles.metadataSection, children: [
4380
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles.metadataTitle, children: [
4381
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LayersIcon, {}),
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, import_jsx_runtime5.jsx)("ul", { style: styles.metadataList, children: referencedLayers.map((layer, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { style: styles.metadataItem, children: [
4385
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: layer.layerName }),
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, import_react4.useCallback)((action) => {
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, import_jsx_runtime5.jsxs)("div", { style: styles.actionsSection, children: [
4404
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.sectionLabel, children: "Acciones Sugeridas" }),
4405
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.actionsGrid, children: response.suggestedActions.map((action, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsxs)("div", { style: styles.actionsSection, children: [
4437
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.sectionLabel, children: "Preguntas Relacionadas" }),
4438
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: response.followUpQuestions.map((question, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsxs)("div", { style: styles.root, children: [
4468
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `
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
- inset: 0 !important;
4512
- width: 100vw !important;
4513
- max-width: 100vw !important;
4514
- height: 100vh !important;
4515
- height: 100dvh !important;
4696
+ left: 0 !important;
4697
+ right: 0 !important;
4698
+ top: 4rem !important;
4699
+ bottom: 0 !important;
4700
+ width: 100% !important;
4701
+ max-width: 100% !important;
4702
+ height: auto !important;
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, import_jsx_runtime5.jsxs)(
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, import_jsx_runtime5.jsxs)("header", { style: styles.header, children: [
4549
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { style: styles.title, children: "Asistente Zenit AI" }),
4550
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles.headerButtons, children: [
4551
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsx)(CollapseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpandIcon, {})
4751
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CollapseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ExpandIcon, {})
4565
4752
  }
4566
4753
  ),
4567
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsx)(CloseIcon, {})
4767
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {})
4581
4768
  }
4582
4769
  )
4583
4770
  ] })
4584
4771
  ] }),
4585
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: messagesContainerRef, className: "zenit-ai-body", style: styles.messages, children: [
4586
- messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsxs)(
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, import_jsx_runtime5.jsx)(MarkdownRenderer, { content: message.content }) : message.content,
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, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
4626
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MarkdownRenderer, { content: streamingText }),
4627
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: styles.cursor })
4628
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles.thinkingText, children: [
4629
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Analizando" }),
4630
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles.typingIndicator, children: [
4631
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
4632
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
4633
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot })
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, import_jsx_runtime5.jsx)("div", { ref: messagesEndRef })
4827
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: messagesEndRef })
4641
4828
  ] }),
4642
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "zenit-ai-input-area", style: styles.inputWrapper, children: [
4643
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsx)(SendIcon, {})
4856
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SendIcon, {})
4670
4857
  }
4671
4858
  )
4672
4859
  ] }),
4673
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.errorText, children: errorMessage }),
4674
- !mapId && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.statusNote, children: "Selecciona un mapa para usar el asistente" }),
4675
- !baseUrl && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.statusNote, children: "Configura la baseUrl del SDK" })
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, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsx)(CloseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
4691
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChatIcon, {}),
4692
- !isMobile && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Asistente IA" })
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, import_react_dom.createPortal)(chatContent, document.body);
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,