zenit-sdk 0.0.2 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-LX2N2BXV.mjs +3258 -0
- package/dist/chunk-LX2N2BXV.mjs.map +1 -0
- package/dist/{chat.service-Dr9qCnuT.d.mts → index-kGwfqTc_.d.mts} +192 -1
- package/dist/{chat.service-Dr9qCnuT.d.ts → index-kGwfqTc_.d.ts} +192 -1
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +2962 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +51 -3
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +3 -183
- package/dist/react/index.d.ts +3 -183
- package/dist/react/index.js +303 -102
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +25 -2712
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-4Y7JCMGR.mjs +0 -330
- package/dist/chunk-4Y7JCMGR.mjs.map +0 -1
package/dist/react/index.js
CHANGED
|
@@ -58,7 +58,7 @@ __export(react_exports, {
|
|
|
58
58
|
module.exports = __toCommonJS(react_exports);
|
|
59
59
|
|
|
60
60
|
// src/react/ZenitMap.tsx
|
|
61
|
-
var import_react = require("react");
|
|
61
|
+
var import_react = __toESM(require("react"));
|
|
62
62
|
var import_react_leaflet = require("react-leaflet");
|
|
63
63
|
var import_leaflet = __toESM(require("leaflet"));
|
|
64
64
|
|
|
@@ -344,6 +344,121 @@ function getFeatureLayerId(feature) {
|
|
|
344
344
|
function escapeHtml(value) {
|
|
345
345
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
346
346
|
}
|
|
347
|
+
var DESCRIPTION_KEYS = /* @__PURE__ */ new Set(["descripcion", "description"]);
|
|
348
|
+
function normalizeDescriptionValue(value) {
|
|
349
|
+
if (value === void 0 || value === null) return null;
|
|
350
|
+
if (typeof value === "string") {
|
|
351
|
+
const trimmed = value.trim();
|
|
352
|
+
return trimmed ? trimmed : null;
|
|
353
|
+
}
|
|
354
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
355
|
+
return String(value);
|
|
356
|
+
}
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
function extractDescriptionValue(properties) {
|
|
360
|
+
if (!properties) return null;
|
|
361
|
+
const matches = Object.entries(properties).find(
|
|
362
|
+
([key]) => DESCRIPTION_KEYS.has(key.toLowerCase())
|
|
363
|
+
);
|
|
364
|
+
if (!matches) return null;
|
|
365
|
+
return normalizeDescriptionValue(matches[1]);
|
|
366
|
+
}
|
|
367
|
+
function safeJsonStringify(value) {
|
|
368
|
+
try {
|
|
369
|
+
const json = JSON.stringify(value, null, 2);
|
|
370
|
+
if (json !== void 0) return json;
|
|
371
|
+
} catch {
|
|
372
|
+
}
|
|
373
|
+
return String(value);
|
|
374
|
+
}
|
|
375
|
+
function renderPropertyValue(value) {
|
|
376
|
+
if (value === null || value === void 0) {
|
|
377
|
+
return '<span class="prop-empty">\u2014</span>';
|
|
378
|
+
}
|
|
379
|
+
if (typeof value === "object") {
|
|
380
|
+
const json = safeJsonStringify(value);
|
|
381
|
+
return `<pre class="prop-json">${escapeHtml(json)}</pre>`;
|
|
382
|
+
}
|
|
383
|
+
return `<span class="prop-text">${escapeHtml(String(value))}</span>`;
|
|
384
|
+
}
|
|
385
|
+
var POPUP_TITLE_KEYS = ["name", "title", "nombre", "label", "id"];
|
|
386
|
+
var POPUP_CHIP_KEYS = /* @__PURE__ */ new Set(["churn", "color", "sector"]);
|
|
387
|
+
function isChipValue(value) {
|
|
388
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
389
|
+
}
|
|
390
|
+
function getSanitizedChipColor(value) {
|
|
391
|
+
if (typeof value !== "string") return null;
|
|
392
|
+
const trimmed = value.trim();
|
|
393
|
+
if (/^#([0-9a-fA-F]{3}){1,2}$/.test(trimmed)) {
|
|
394
|
+
return trimmed;
|
|
395
|
+
}
|
|
396
|
+
if (/^rgb\((\s*\d+\s*,){2}\s*\d+\s*\)$/.test(trimmed)) {
|
|
397
|
+
return trimmed;
|
|
398
|
+
}
|
|
399
|
+
if (/^rgba\((\s*\d+\s*,){3}\s*(0|1|0?\.\d+)\s*\)$/.test(trimmed)) {
|
|
400
|
+
return trimmed;
|
|
401
|
+
}
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
function getPopupTitle(entries) {
|
|
405
|
+
for (const candidate of POPUP_TITLE_KEYS) {
|
|
406
|
+
const match = entries.find((entry) => entry.normalized === candidate);
|
|
407
|
+
if (!match || match.value === null || match.value === void 0) continue;
|
|
408
|
+
const value = String(match.value).trim();
|
|
409
|
+
if (!value) continue;
|
|
410
|
+
return { title: value, key: match.key };
|
|
411
|
+
}
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
function renderProperties(properties) {
|
|
415
|
+
const description = extractDescriptionValue(properties);
|
|
416
|
+
const entries = Object.entries(properties).filter(([key]) => !DESCRIPTION_KEYS.has(key.toLowerCase())).map(([key, value]) => ({
|
|
417
|
+
key,
|
|
418
|
+
value,
|
|
419
|
+
normalized: key.trim().toLowerCase()
|
|
420
|
+
}));
|
|
421
|
+
if (!description && entries.length === 0) return "";
|
|
422
|
+
const titleEntry = getPopupTitle(entries);
|
|
423
|
+
const titleText = titleEntry?.title ?? "Detalle del elemento";
|
|
424
|
+
const chipEntries = entries.filter(
|
|
425
|
+
(entry) => POPUP_CHIP_KEYS.has(entry.normalized) && isChipValue(entry.value)
|
|
426
|
+
);
|
|
427
|
+
const listEntries = entries.filter((entry) => {
|
|
428
|
+
if (titleEntry && entry.key === titleEntry.key) return false;
|
|
429
|
+
if (chipEntries.find((chip) => chip.key === entry.key)) return false;
|
|
430
|
+
return true;
|
|
431
|
+
});
|
|
432
|
+
const descriptionHtml = description ? `<div class="popup-description">${escapeHtml(description)}</div>` : "";
|
|
433
|
+
const chipsHtml = chipEntries.length ? `<div class="popup-chip-row">${chipEntries.map((entry) => {
|
|
434
|
+
const label = escapeHtml(entry.key.replace(/_/g, " "));
|
|
435
|
+
const value = escapeHtml(String(entry.value));
|
|
436
|
+
const color = getSanitizedChipColor(entry.value);
|
|
437
|
+
const colorStyle = color ? ` style="--chip-color: ${color}"` : "";
|
|
438
|
+
return `<span class="popup-chip"${colorStyle}><span class="popup-chip-label">${label}</span><span class="popup-chip-value">${value}</span></span>`;
|
|
439
|
+
}).join("")}</div>` : "";
|
|
440
|
+
const rowsHtml = listEntries.map((entry) => {
|
|
441
|
+
const label = escapeHtml(entry.key.replace(/_/g, " "));
|
|
442
|
+
const valueHtml = renderPropertyValue(entry.value);
|
|
443
|
+
return `<div class="prop-key">${label}</div><div class="prop-value">${valueHtml}</div>`;
|
|
444
|
+
}).join("");
|
|
445
|
+
const listHtml = rowsHtml ? `<div class="prop-list">${rowsHtml}</div>` : "";
|
|
446
|
+
return `
|
|
447
|
+
<div class="feature-popup">
|
|
448
|
+
<div class="feature-popup-card">
|
|
449
|
+
<div class="feature-popup-header">
|
|
450
|
+
<p class="popup-eyebrow">Informaci\xF3n</p>
|
|
451
|
+
<h3 class="popup-title">${escapeHtml(titleText)}</h3>
|
|
452
|
+
</div>
|
|
453
|
+
<div class="feature-popup-body">
|
|
454
|
+
${descriptionHtml}
|
|
455
|
+
${chipsHtml}
|
|
456
|
+
${listHtml}
|
|
457
|
+
</div>
|
|
458
|
+
</div>
|
|
459
|
+
</div>
|
|
460
|
+
`;
|
|
461
|
+
}
|
|
347
462
|
function withAlpha(color, alpha) {
|
|
348
463
|
const trimmed = color.trim();
|
|
349
464
|
if (trimmed.startsWith("#")) {
|
|
@@ -412,40 +527,39 @@ function getFeatureStyleOverrides(feature) {
|
|
|
412
527
|
function buildFeaturePopupHtml(feature) {
|
|
413
528
|
const properties = feature?.properties;
|
|
414
529
|
if (!properties) return null;
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
if (
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
const val = escapeHtml(String(value));
|
|
444
|
-
return `<div><strong>${label}:</strong> ${val}</div>`;
|
|
445
|
-
}).join("");
|
|
446
|
-
parts.push(`<div style="font-size:12px;line-height:1.4;">${rows}</div>`);
|
|
530
|
+
const rendered = renderProperties(properties);
|
|
531
|
+
return rendered ? rendered : null;
|
|
532
|
+
}
|
|
533
|
+
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
534
|
+
function getGeometryType(feature) {
|
|
535
|
+
const t = feature?.geometry?.type;
|
|
536
|
+
return typeof t === "string" ? t : null;
|
|
537
|
+
}
|
|
538
|
+
function isPointGeometry(feature) {
|
|
539
|
+
const geometryType = getGeometryType(feature);
|
|
540
|
+
return geometryType !== null && POINT_GEOMETRY_TYPES.has(geometryType);
|
|
541
|
+
}
|
|
542
|
+
function isNonPointGeometry(feature) {
|
|
543
|
+
const geometryType = getGeometryType(feature);
|
|
544
|
+
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
545
|
+
}
|
|
546
|
+
function buildFeatureCollection(features) {
|
|
547
|
+
return {
|
|
548
|
+
type: "FeatureCollection",
|
|
549
|
+
features
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function pickIntersectFeature(baseFeature, candidates) {
|
|
553
|
+
if (!Array.isArray(candidates) || candidates.length === 0) return null;
|
|
554
|
+
const baseId = baseFeature?.id;
|
|
555
|
+
if (baseId !== void 0 && baseId !== null) {
|
|
556
|
+
const matchById = candidates.find((candidate) => candidate?.id === baseId);
|
|
557
|
+
if (matchById) return matchById;
|
|
447
558
|
}
|
|
448
|
-
|
|
559
|
+
const matchWithDescription = candidates.find(
|
|
560
|
+
(candidate) => extractDescriptionValue(candidate?.properties)
|
|
561
|
+
);
|
|
562
|
+
return matchWithDescription ?? candidates[0];
|
|
449
563
|
}
|
|
450
564
|
function normalizeCenterTuple(center) {
|
|
451
565
|
if (!center) return null;
|
|
@@ -566,6 +680,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
566
680
|
const [loadingMap, setLoadingMap] = (0, import_react.useState)(false);
|
|
567
681
|
const [mapError, setMapError] = (0, import_react.useState)(null);
|
|
568
682
|
const [mapInstance, setMapInstance] = (0, import_react.useState)(null);
|
|
683
|
+
const [panesReady, setPanesReady] = (0, import_react.useState)(false);
|
|
569
684
|
const [currentZoom, setCurrentZoom] = (0, import_react.useState)(initialZoom ?? DEFAULT_ZOOM);
|
|
570
685
|
const [isMobile, setIsMobile] = (0, import_react.useState)(() => {
|
|
571
686
|
if (typeof window === "undefined") return false;
|
|
@@ -880,16 +995,23 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
880
995
|
(targetMap, targetLayers) => {
|
|
881
996
|
const baseZIndex = 400;
|
|
882
997
|
targetLayers.forEach((layer) => {
|
|
883
|
-
const paneName = `zenit-layer-${layer.layerId}`;
|
|
884
|
-
const pane = targetMap.getPane(paneName) ?? targetMap.createPane(paneName);
|
|
885
998
|
const order = Number.isFinite(layer.displayOrder) ? layer.displayOrder : 0;
|
|
886
|
-
|
|
999
|
+
const fillPaneName = `zenit-layer-${layer.layerId}-fill`;
|
|
1000
|
+
const pointPaneName = `zenit-layer-${layer.layerId}-points`;
|
|
1001
|
+
const labelPaneName = `zenit-layer-${layer.layerId}-labels`;
|
|
1002
|
+
const fillPane = targetMap.getPane(fillPaneName) ?? targetMap.createPane(fillPaneName);
|
|
1003
|
+
const pointPane = targetMap.getPane(pointPaneName) ?? targetMap.createPane(pointPaneName);
|
|
1004
|
+
const labelPane = targetMap.getPane(labelPaneName) ?? targetMap.createPane(labelPaneName);
|
|
1005
|
+
fillPane.style.zIndex = String(baseZIndex + order);
|
|
1006
|
+
pointPane.style.zIndex = String(baseZIndex + order + 1e3);
|
|
1007
|
+
labelPane.style.zIndex = String(baseZIndex + order + 2e3);
|
|
887
1008
|
});
|
|
888
1009
|
},
|
|
889
1010
|
[]
|
|
890
1011
|
);
|
|
891
1012
|
const handleMapReady = (0, import_react.useCallback)(
|
|
892
1013
|
(instance) => {
|
|
1014
|
+
setPanesReady(false);
|
|
893
1015
|
setMapInstance(instance);
|
|
894
1016
|
onMapReady?.(instance);
|
|
895
1017
|
},
|
|
@@ -897,6 +1019,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
897
1019
|
);
|
|
898
1020
|
(0, import_react.useEffect)(() => {
|
|
899
1021
|
if (!mapInstance) {
|
|
1022
|
+
setPanesReady(false);
|
|
900
1023
|
return;
|
|
901
1024
|
}
|
|
902
1025
|
if (orderedLayers.length === 0) {
|
|
@@ -907,6 +1030,11 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
907
1030
|
displayOrder: layer.displayOrder
|
|
908
1031
|
}));
|
|
909
1032
|
ensureLayerPanes(mapInstance, layerTargets);
|
|
1033
|
+
const first = layerTargets[0];
|
|
1034
|
+
const testPane = mapInstance.getPane(`zenit-layer-${first.layerId}-labels`);
|
|
1035
|
+
if (testPane) {
|
|
1036
|
+
setPanesReady(true);
|
|
1037
|
+
}
|
|
910
1038
|
}, [mapInstance, orderedLayers, ensureLayerPanes]);
|
|
911
1039
|
const overlayOnEachFeature = (0, import_react.useMemo)(() => {
|
|
912
1040
|
return (feature, layer) => {
|
|
@@ -924,7 +1052,14 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
924
1052
|
if (featureInfoMode === "popup") {
|
|
925
1053
|
const content = buildFeaturePopupHtml(feature);
|
|
926
1054
|
if (content) {
|
|
927
|
-
layer.bindPopup(content, {
|
|
1055
|
+
layer.bindPopup(content, {
|
|
1056
|
+
maxWidth: 420,
|
|
1057
|
+
minWidth: 280,
|
|
1058
|
+
className: "zenit-feature-popup-shell",
|
|
1059
|
+
autoPan: true,
|
|
1060
|
+
closeButton: true,
|
|
1061
|
+
offset: import_leaflet.default.point(0, -24)
|
|
1062
|
+
});
|
|
928
1063
|
}
|
|
929
1064
|
}
|
|
930
1065
|
if (isPointFeature && layer.bindTooltip) {
|
|
@@ -935,7 +1070,37 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
935
1070
|
className: "zenit-map-tooltip"
|
|
936
1071
|
});
|
|
937
1072
|
}
|
|
938
|
-
layer.on("click", () =>
|
|
1073
|
+
layer.on("click", () => {
|
|
1074
|
+
if (featureInfoMode === "popup" && client && layerId !== void 0 && !extractDescriptionValue(feature?.properties) && feature?.geometry) {
|
|
1075
|
+
const trackedFeature = feature;
|
|
1076
|
+
if (!trackedFeature.__zenit_popup_loaded) {
|
|
1077
|
+
trackedFeature.__zenit_popup_loaded = true;
|
|
1078
|
+
client.layers.getLayerGeoJsonIntersect({
|
|
1079
|
+
id: layerId,
|
|
1080
|
+
geometry: feature.geometry
|
|
1081
|
+
}).then((response) => {
|
|
1082
|
+
const candidates = response.data?.features ?? [];
|
|
1083
|
+
const resolved = pickIntersectFeature(feature, candidates);
|
|
1084
|
+
if (!resolved?.properties) return;
|
|
1085
|
+
const mergedProperties = {
|
|
1086
|
+
...trackedFeature.properties ?? {},
|
|
1087
|
+
...resolved.properties
|
|
1088
|
+
};
|
|
1089
|
+
trackedFeature.properties = mergedProperties;
|
|
1090
|
+
const updatedHtml = buildFeaturePopupHtml({
|
|
1091
|
+
...feature,
|
|
1092
|
+
properties: mergedProperties
|
|
1093
|
+
});
|
|
1094
|
+
if (updatedHtml && layer.setPopupContent) {
|
|
1095
|
+
layer.setPopupContent(updatedHtml);
|
|
1096
|
+
}
|
|
1097
|
+
}).catch(() => {
|
|
1098
|
+
trackedFeature.__zenit_popup_loaded = false;
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
onFeatureClick?.(feature, layerId);
|
|
1103
|
+
});
|
|
939
1104
|
layer.on("mouseover", () => {
|
|
940
1105
|
if (layer instanceof import_leaflet.default.Path && originalStyle) {
|
|
941
1106
|
layer.setStyle({
|
|
@@ -959,7 +1124,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
959
1124
|
}
|
|
960
1125
|
});
|
|
961
1126
|
};
|
|
962
|
-
}, [featureInfoMode, onFeatureClick, onFeatureHover]);
|
|
1127
|
+
}, [client, featureInfoMode, onFeatureClick, onFeatureHover]);
|
|
963
1128
|
const buildLayerStyle = (layerId, baseOpacity, feature, layerType) => {
|
|
964
1129
|
const style = resolveLayerStyle(layerId);
|
|
965
1130
|
const featureStyleOverrides = getFeatureStyleOverrides(feature);
|
|
@@ -1140,22 +1305,50 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1140
1305
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ZoomBasedOpacityHandler, { onZoomChange: handleZoomChange }),
|
|
1141
1306
|
orderedLayers.map((layerState) => {
|
|
1142
1307
|
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
1143
|
-
const
|
|
1308
|
+
const fillPaneName = `zenit-layer-${layerState.mapLayer.layerId}-fill`;
|
|
1309
|
+
const pointsPaneName = `zenit-layer-${layerState.mapLayer.layerId}-points`;
|
|
1310
|
+
const labelPaneName = `zenit-layer-${layerState.mapLayer.layerId}-labels`;
|
|
1144
1311
|
const layerType = layerState.layer?.layerType ?? layerState.mapLayer.layerType ?? void 0;
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1312
|
+
const data = layerState.data?.features ?? [];
|
|
1313
|
+
const fillFeatures = data.filter(isNonPointGeometry);
|
|
1314
|
+
const pointFeatures = data.filter(isPointGeometry);
|
|
1315
|
+
const fillData = fillFeatures.length > 0 ? buildFeatureCollection(fillFeatures) : null;
|
|
1316
|
+
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
1317
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.default.Fragment, { children: [
|
|
1318
|
+
fillData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1319
|
+
import_react_leaflet.GeoJSON,
|
|
1320
|
+
{
|
|
1321
|
+
data: fillData,
|
|
1322
|
+
pane: panesReady && mapInstance?.getPane(fillPaneName) ? fillPaneName : void 0,
|
|
1323
|
+
style: (feature) => buildLayerStyle(layerState.mapLayer.layerId, baseOpacity, feature, layerType),
|
|
1324
|
+
onEachFeature: overlayOnEachFeature
|
|
1325
|
+
}
|
|
1326
|
+
),
|
|
1327
|
+
pointsData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1328
|
+
import_react_leaflet.GeoJSON,
|
|
1329
|
+
{
|
|
1330
|
+
data: pointsData,
|
|
1331
|
+
pane: panesReady && mapInstance?.getPane(pointsPaneName) ? pointsPaneName : void 0,
|
|
1332
|
+
pointToLayer: (feature, latlng) => import_leaflet.default.circleMarker(latlng, {
|
|
1333
|
+
radius: isMobile ? 8 : 6,
|
|
1334
|
+
...buildLayerStyle(layerState.mapLayer.layerId, baseOpacity, feature, layerType)
|
|
1335
|
+
}),
|
|
1336
|
+
onEachFeature: overlayOnEachFeature
|
|
1337
|
+
}
|
|
1338
|
+
),
|
|
1339
|
+
panesReady && mapInstance?.getPane(labelPaneName) ? labelMarkers.filter(
|
|
1340
|
+
(marker) => String(marker.layerId) === String(layerState.mapLayer.layerId)
|
|
1341
|
+
).map((marker) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1342
|
+
import_react_leaflet.Marker,
|
|
1343
|
+
{
|
|
1344
|
+
position: marker.position,
|
|
1345
|
+
icon: buildLabelIcon(marker.label, marker.opacity, marker.color),
|
|
1346
|
+
interactive: false,
|
|
1347
|
+
pane: labelPaneName
|
|
1348
|
+
},
|
|
1349
|
+
marker.key
|
|
1350
|
+
)) : null
|
|
1351
|
+
] }, layerState.mapLayer.layerId.toString());
|
|
1159
1352
|
}),
|
|
1160
1353
|
overlayGeojson && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1161
1354
|
import_react_leaflet.GeoJSON,
|
|
@@ -1165,16 +1358,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1165
1358
|
onEachFeature: overlayOnEachFeature
|
|
1166
1359
|
},
|
|
1167
1360
|
"zenit-overlay-geojson"
|
|
1168
|
-
)
|
|
1169
|
-
labelMarkers.map((marker) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1170
|
-
import_react_leaflet.Marker,
|
|
1171
|
-
{
|
|
1172
|
-
position: marker.position,
|
|
1173
|
-
icon: buildLabelIcon(marker.label, marker.opacity, marker.color),
|
|
1174
|
-
interactive: false
|
|
1175
|
-
},
|
|
1176
|
-
marker.key
|
|
1177
|
-
))
|
|
1361
|
+
)
|
|
1178
1362
|
]
|
|
1179
1363
|
},
|
|
1180
1364
|
String(mapId)
|
|
@@ -2330,6 +2514,11 @@ var styles = {
|
|
|
2330
2514
|
height: 56,
|
|
2331
2515
|
padding: 0
|
|
2332
2516
|
},
|
|
2517
|
+
floatingButtonMobile: {
|
|
2518
|
+
width: 56,
|
|
2519
|
+
height: 56,
|
|
2520
|
+
padding: 0
|
|
2521
|
+
},
|
|
2333
2522
|
// Panel (expandable)
|
|
2334
2523
|
panel: {
|
|
2335
2524
|
position: "fixed",
|
|
@@ -2579,9 +2768,21 @@ var FloatingChatBox = ({
|
|
|
2579
2768
|
baseUrl,
|
|
2580
2769
|
accessToken,
|
|
2581
2770
|
getAccessToken,
|
|
2582
|
-
onActionClick
|
|
2771
|
+
onActionClick,
|
|
2772
|
+
onOpenChange,
|
|
2773
|
+
hideButton,
|
|
2774
|
+
open: openProp
|
|
2583
2775
|
}) => {
|
|
2584
|
-
const
|
|
2776
|
+
const isControlled = openProp !== void 0;
|
|
2777
|
+
const [internalOpen, setInternalOpen] = (0, import_react4.useState)(false);
|
|
2778
|
+
const open = isControlled ? openProp : internalOpen;
|
|
2779
|
+
const setOpen = (0, import_react4.useCallback)((value) => {
|
|
2780
|
+
const newValue = typeof value === "function" ? value(open) : value;
|
|
2781
|
+
if (!isControlled) {
|
|
2782
|
+
setInternalOpen(newValue);
|
|
2783
|
+
}
|
|
2784
|
+
onOpenChange?.(newValue);
|
|
2785
|
+
}, [isControlled, open, onOpenChange]);
|
|
2585
2786
|
const [expanded, setExpanded] = (0, import_react4.useState)(false);
|
|
2586
2787
|
const [messages, setMessages] = (0, import_react4.useState)([]);
|
|
2587
2788
|
const [inputValue, setInputValue] = (0, import_react4.useState)("");
|
|
@@ -2598,6 +2799,11 @@ var FloatingChatBox = ({
|
|
|
2598
2799
|
}, [accessToken, baseUrl, getAccessToken]);
|
|
2599
2800
|
const { sendMessage: sendMessage2, isStreaming, streamingText, completeResponse } = useSendMessageStream(chatConfig);
|
|
2600
2801
|
const canSend = Boolean(mapId) && Boolean(baseUrl) && inputValue.trim().length > 0 && !isStreaming;
|
|
2802
|
+
(0, import_react4.useEffect)(() => {
|
|
2803
|
+
if (open && isMobile) {
|
|
2804
|
+
setExpanded(true);
|
|
2805
|
+
}
|
|
2806
|
+
}, [open, isMobile]);
|
|
2601
2807
|
const scrollToBottom = (0, import_react4.useCallback)(() => {
|
|
2602
2808
|
if (messagesEndRef.current) {
|
|
2603
2809
|
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
@@ -2619,8 +2825,9 @@ var FloatingChatBox = ({
|
|
|
2619
2825
|
}, [messages, streamingText, scrollToBottom]);
|
|
2620
2826
|
(0, import_react4.useEffect)(() => {
|
|
2621
2827
|
if (!open) return;
|
|
2828
|
+
if (isMobile && expanded) return;
|
|
2622
2829
|
const handleClickOutside = (event) => {
|
|
2623
|
-
if (
|
|
2830
|
+
if (chatBoxRef.current && !chatBoxRef.current.contains(event.target)) {
|
|
2624
2831
|
setOpen(false);
|
|
2625
2832
|
}
|
|
2626
2833
|
};
|
|
@@ -2628,7 +2835,7 @@ var FloatingChatBox = ({
|
|
|
2628
2835
|
return () => {
|
|
2629
2836
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
2630
2837
|
};
|
|
2631
|
-
}, [open]);
|
|
2838
|
+
}, [open, isMobile, expanded]);
|
|
2632
2839
|
(0, import_react4.useEffect)(() => {
|
|
2633
2840
|
if (typeof window === "undefined") return;
|
|
2634
2841
|
const mediaQuery = window.matchMedia("(max-width: 768px)");
|
|
@@ -2648,31 +2855,13 @@ var FloatingChatBox = ({
|
|
|
2648
2855
|
};
|
|
2649
2856
|
}, []);
|
|
2650
2857
|
(0, import_react4.useEffect)(() => {
|
|
2651
|
-
if (typeof
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
const updateOverflow = () => {
|
|
2655
|
-
if (open && expanded && mediaQuery.matches) {
|
|
2656
|
-
document.body.style.overflow = "hidden";
|
|
2657
|
-
} else {
|
|
2658
|
-
document.body.style.overflow = originalOverflow;
|
|
2659
|
-
}
|
|
2660
|
-
};
|
|
2661
|
-
updateOverflow();
|
|
2662
|
-
if (mediaQuery.addEventListener) {
|
|
2663
|
-
mediaQuery.addEventListener("change", updateOverflow);
|
|
2664
|
-
} else {
|
|
2665
|
-
mediaQuery.addListener(updateOverflow);
|
|
2666
|
-
}
|
|
2858
|
+
if (typeof document === "undefined") return;
|
|
2859
|
+
if (!open || !isMobile) return;
|
|
2860
|
+
document.body.style.overflow = "hidden";
|
|
2667
2861
|
return () => {
|
|
2668
|
-
|
|
2669
|
-
mediaQuery.removeEventListener("change", updateOverflow);
|
|
2670
|
-
} else {
|
|
2671
|
-
mediaQuery.removeListener(updateOverflow);
|
|
2672
|
-
}
|
|
2673
|
-
document.body.style.overflow = originalOverflow;
|
|
2862
|
+
document.body.style.overflow = "";
|
|
2674
2863
|
};
|
|
2675
|
-
}, [open,
|
|
2864
|
+
}, [open, isMobile]);
|
|
2676
2865
|
const addMessage = (0, import_react4.useCallback)((message) => {
|
|
2677
2866
|
setMessages((prev) => [...prev, message]);
|
|
2678
2867
|
}, []);
|
|
@@ -2762,6 +2951,13 @@ var FloatingChatBox = ({
|
|
|
2762
2951
|
] }, index)) })
|
|
2763
2952
|
] });
|
|
2764
2953
|
};
|
|
2954
|
+
const handleActionClick = (0, import_react4.useCallback)((action) => {
|
|
2955
|
+
if (isStreaming) return;
|
|
2956
|
+
setOpen(false);
|
|
2957
|
+
requestAnimationFrame(() => {
|
|
2958
|
+
onActionClick?.(action);
|
|
2959
|
+
});
|
|
2960
|
+
}, [isStreaming, setOpen, onActionClick]);
|
|
2765
2961
|
const renderActions = (response) => {
|
|
2766
2962
|
if (!response?.suggestedActions?.length) return null;
|
|
2767
2963
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles.actionsSection, children: [
|
|
@@ -2775,7 +2971,7 @@ var FloatingChatBox = ({
|
|
|
2775
2971
|
opacity: isStreaming ? 0.5 : 1,
|
|
2776
2972
|
cursor: isStreaming ? "not-allowed" : "pointer"
|
|
2777
2973
|
},
|
|
2778
|
-
onClick: () =>
|
|
2974
|
+
onClick: () => handleActionClick(action),
|
|
2779
2975
|
disabled: isStreaming,
|
|
2780
2976
|
onMouseEnter: (e) => {
|
|
2781
2977
|
if (!isStreaming) {
|
|
@@ -2881,13 +3077,18 @@ var FloatingChatBox = ({
|
|
|
2881
3077
|
display: flex !important;
|
|
2882
3078
|
flex-direction: column !important;
|
|
2883
3079
|
overflow: hidden !important;
|
|
2884
|
-
z-index:
|
|
3080
|
+
z-index: 100000 !important;
|
|
2885
3081
|
padding-top: env(safe-area-inset-top);
|
|
2886
|
-
padding-bottom: env(safe-area-inset-bottom);
|
|
2887
3082
|
}
|
|
2888
3083
|
.zenit-chat-panel.zenit-chat-panel--fullscreen .zenit-ai-body {
|
|
2889
3084
|
flex: 1;
|
|
2890
|
-
|
|
3085
|
+
min-height: 0;
|
|
3086
|
+
overflow-y: auto;
|
|
3087
|
+
-webkit-overflow-scrolling: touch;
|
|
3088
|
+
}
|
|
3089
|
+
.zenit-chat-panel.zenit-chat-panel--fullscreen .zenit-ai-input-area {
|
|
3090
|
+
flex-shrink: 0;
|
|
3091
|
+
padding-bottom: max(14px, env(safe-area-inset-bottom));
|
|
2891
3092
|
}
|
|
2892
3093
|
.zenit-ai-button.zenit-ai-button--hidden-mobile {
|
|
2893
3094
|
display: none !important;
|
|
@@ -2898,7 +3099,7 @@ var FloatingChatBox = ({
|
|
|
2898
3099
|
"div",
|
|
2899
3100
|
{
|
|
2900
3101
|
ref: chatBoxRef,
|
|
2901
|
-
className: `zenit-chat-panel${expanded ? " zenit-chat-panel--expanded" : ""}${
|
|
3102
|
+
className: `zenit-chat-panel${expanded ? " zenit-chat-panel--expanded" : ""}${isMobile ? " zenit-chat-panel--fullscreen" : ""}`,
|
|
2902
3103
|
style: {
|
|
2903
3104
|
...styles.panel,
|
|
2904
3105
|
...expanded ? styles.panelExpanded : styles.panelNormal
|
|
@@ -2998,7 +3199,7 @@ var FloatingChatBox = ({
|
|
|
2998
3199
|
),
|
|
2999
3200
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: messagesEndRef })
|
|
3000
3201
|
] }),
|
|
3001
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles.inputWrapper, children: [
|
|
3202
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "zenit-ai-input-area", style: styles.inputWrapper, children: [
|
|
3002
3203
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3003
3204
|
"textarea",
|
|
3004
3205
|
{
|
|
@@ -3035,20 +3236,20 @@ var FloatingChatBox = ({
|
|
|
3035
3236
|
]
|
|
3036
3237
|
}
|
|
3037
3238
|
),
|
|
3038
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3239
|
+
!(hideButton && !open) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3039
3240
|
"button",
|
|
3040
3241
|
{
|
|
3041
3242
|
type: "button",
|
|
3042
|
-
className: `zenit-ai-button ${open ? "open" : ""}${open &&
|
|
3243
|
+
className: `zenit-ai-button ${open ? "open" : ""}${open && isMobile ? " zenit-ai-button--hidden-mobile" : ""}`,
|
|
3043
3244
|
style: {
|
|
3044
3245
|
...styles.floatingButton,
|
|
3045
|
-
...open ? styles.floatingButtonOpen : styles.floatingButtonClosed
|
|
3246
|
+
...open ? styles.floatingButtonOpen : isMobile ? styles.floatingButtonMobile : styles.floatingButtonClosed
|
|
3046
3247
|
},
|
|
3047
3248
|
onClick: () => setOpen((prev) => !prev),
|
|
3048
3249
|
"aria-label": open ? "Cerrar asistente" : "Abrir asistente Zenit AI",
|
|
3049
3250
|
children: open ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CloseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
3050
3251
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChatIcon, {}),
|
|
3051
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Asistente IA" })
|
|
3252
|
+
!isMobile && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Asistente IA" })
|
|
3052
3253
|
] })
|
|
3053
3254
|
}
|
|
3054
3255
|
)
|