zenit-sdk 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/{chunk-ITF7QCUZ.mjs → chunk-PCTRVN4O.mjs} +1140 -926
- package/dist/chunk-PCTRVN4O.mjs.map +1 -0
- package/dist/{index-kGwfqTc_.d.mts → index-DvcYGhqj.d.mts} +70 -4
- package/dist/{index-kGwfqTc_.d.ts → index-DvcYGhqj.d.ts} +70 -4
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1272 -937
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +119 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +1154 -940
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1 -1
- package/package.json +10 -7
- package/dist/chunk-ITF7QCUZ.mjs.map +0 -1
package/dist/react/index.js
CHANGED
|
@@ -58,9 +58,9 @@ __export(react_exports, {
|
|
|
58
58
|
module.exports = __toCommonJS(react_exports);
|
|
59
59
|
|
|
60
60
|
// src/react/ZenitMap.tsx
|
|
61
|
-
var
|
|
62
|
-
var
|
|
63
|
-
var
|
|
61
|
+
var import_react4 = __toESM(require("react"));
|
|
62
|
+
var import_react_leaflet4 = require("react-leaflet");
|
|
63
|
+
var import_leaflet4 = __toESM(require("leaflet"));
|
|
64
64
|
|
|
65
65
|
// src/maps/helpers.ts
|
|
66
66
|
function toNumber(value) {
|
|
@@ -253,9 +253,9 @@ function getAccentByLayerId(layerId, mapLayers) {
|
|
|
253
253
|
|
|
254
254
|
// src/react/zoomOpacity.ts
|
|
255
255
|
var DEFAULT_OPTIONS = {
|
|
256
|
-
minZoom:
|
|
257
|
-
maxZoom:
|
|
258
|
-
minFactor: 0.
|
|
256
|
+
minZoom: 11,
|
|
257
|
+
maxZoom: 15,
|
|
258
|
+
minFactor: 0.3,
|
|
259
259
|
maxFactor: 1,
|
|
260
260
|
minOpacity: 0.1,
|
|
261
261
|
maxOpacity: 0.92
|
|
@@ -292,302 +292,215 @@ function getEffectiveLayerOpacity(baseOpacity, zoom, layerType, geometryType, op
|
|
|
292
292
|
return clampNumber(effective, settings.minOpacity, settings.maxOpacity);
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
// src/react/
|
|
295
|
+
// src/react/map/layer-geojson.tsx
|
|
296
|
+
var import_react_leaflet = require("react-leaflet");
|
|
297
|
+
var import_leaflet = __toESM(require("leaflet"));
|
|
296
298
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
297
|
-
var
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
if (!Array.isArray(geojson.features) || geojson.features.length === 0) return null;
|
|
302
|
-
const coords = [];
|
|
303
|
-
const collect = (candidate) => {
|
|
304
|
-
if (!Array.isArray(candidate)) return;
|
|
305
|
-
if (candidate.length === 2 && typeof candidate[0] === "number" && typeof candidate[1] === "number") {
|
|
306
|
-
coords.push([candidate[0], candidate[1]]);
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
candidate.forEach((entry) => collect(entry));
|
|
310
|
-
};
|
|
311
|
-
geojson.features.forEach((feature) => {
|
|
312
|
-
collect(feature.geometry?.coordinates);
|
|
313
|
-
});
|
|
314
|
-
if (coords.length === 0) return null;
|
|
315
|
-
const [firstLon, firstLat] = coords[0];
|
|
316
|
-
const bbox = { minLon: firstLon, minLat: firstLat, maxLon: firstLon, maxLat: firstLat };
|
|
317
|
-
coords.forEach(([lon, lat]) => {
|
|
318
|
-
bbox.minLon = Math.min(bbox.minLon, lon);
|
|
319
|
-
bbox.minLat = Math.min(bbox.minLat, lat);
|
|
320
|
-
bbox.maxLon = Math.max(bbox.maxLon, lon);
|
|
321
|
-
bbox.maxLat = Math.max(bbox.maxLat, lat);
|
|
322
|
-
});
|
|
323
|
-
return bbox;
|
|
299
|
+
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
300
|
+
function getGeometryType(feature) {
|
|
301
|
+
const t = feature?.geometry?.type;
|
|
302
|
+
return typeof t === "string" ? t : null;
|
|
324
303
|
}
|
|
325
|
-
function
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
const first = valid[0];
|
|
329
|
-
return valid.slice(1).reduce(
|
|
330
|
-
(acc, bbox) => ({
|
|
331
|
-
minLon: Math.min(acc.minLon, bbox.minLon),
|
|
332
|
-
minLat: Math.min(acc.minLat, bbox.minLat),
|
|
333
|
-
maxLon: Math.max(acc.maxLon, bbox.maxLon),
|
|
334
|
-
maxLat: Math.max(acc.maxLat, bbox.maxLat)
|
|
335
|
-
}),
|
|
336
|
-
{ ...first }
|
|
337
|
-
);
|
|
304
|
+
function isPointGeometry(feature) {
|
|
305
|
+
const geometryType = getGeometryType(feature);
|
|
306
|
+
return geometryType !== null && POINT_GEOMETRY_TYPES.has(geometryType);
|
|
338
307
|
}
|
|
339
|
-
function
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
return layerId;
|
|
308
|
+
function isNonPointGeometry(feature) {
|
|
309
|
+
const geometryType = getGeometryType(feature);
|
|
310
|
+
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
343
311
|
}
|
|
344
|
-
function
|
|
345
|
-
return
|
|
312
|
+
function buildFeatureCollection(features) {
|
|
313
|
+
return {
|
|
314
|
+
type: "FeatureCollection",
|
|
315
|
+
features
|
|
316
|
+
};
|
|
346
317
|
}
|
|
347
|
-
var
|
|
348
|
-
|
|
318
|
+
var LayerGeoJson = ({
|
|
319
|
+
layerId,
|
|
320
|
+
data,
|
|
321
|
+
baseOpacity,
|
|
322
|
+
isMobile,
|
|
323
|
+
panesReady,
|
|
324
|
+
mapInstance,
|
|
325
|
+
fillPaneName,
|
|
326
|
+
pointsPaneName,
|
|
327
|
+
layerType,
|
|
328
|
+
styleFn,
|
|
329
|
+
onEachFeature,
|
|
330
|
+
onPolygonLabel
|
|
331
|
+
}) => {
|
|
332
|
+
const features = data.features ?? [];
|
|
333
|
+
const fillFeatures = features.filter(isNonPointGeometry);
|
|
334
|
+
const pointFeatures = features.filter(isPointGeometry);
|
|
335
|
+
const fillData = fillFeatures.length > 0 ? buildFeatureCollection(fillFeatures) : null;
|
|
336
|
+
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
337
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
338
|
+
fillData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
339
|
+
import_react_leaflet.GeoJSON,
|
|
340
|
+
{
|
|
341
|
+
data: fillData,
|
|
342
|
+
pane: panesReady && mapInstance?.getPane(fillPaneName) ? fillPaneName : void 0,
|
|
343
|
+
style: (feature) => styleFn(feature, layerType, baseOpacity),
|
|
344
|
+
onEachFeature: (feature, layer) => {
|
|
345
|
+
onEachFeature(feature, layer);
|
|
346
|
+
onPolygonLabel?.(feature, layer);
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
`fill-${layerId}`
|
|
350
|
+
),
|
|
351
|
+
pointsData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
352
|
+
import_react_leaflet.GeoJSON,
|
|
353
|
+
{
|
|
354
|
+
data: pointsData,
|
|
355
|
+
pane: panesReady && mapInstance?.getPane(pointsPaneName) ? pointsPaneName : void 0,
|
|
356
|
+
pointToLayer: (feature, latlng) => import_leaflet.default.circleMarker(latlng, {
|
|
357
|
+
radius: isMobile ? 8 : 6,
|
|
358
|
+
...styleFn(feature, layerType, baseOpacity)
|
|
359
|
+
}),
|
|
360
|
+
onEachFeature
|
|
361
|
+
},
|
|
362
|
+
`points-${layerId}`
|
|
363
|
+
)
|
|
364
|
+
] });
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
// src/react/map/location-control.tsx
|
|
368
|
+
var import_react2 = require("react");
|
|
369
|
+
var import_react_dom = require("react-dom");
|
|
370
|
+
var import_react_leaflet2 = require("react-leaflet");
|
|
371
|
+
var import_leaflet3 = __toESM(require("leaflet"));
|
|
372
|
+
|
|
373
|
+
// src/react/hooks/use-geolocation.ts
|
|
374
|
+
var import_react = require("react");
|
|
375
|
+
function useGeolocation(options) {
|
|
376
|
+
const [isTracking, setIsTracking] = (0, import_react.useState)(false);
|
|
377
|
+
const [location, setLocation] = (0, import_react.useState)(null);
|
|
378
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
379
|
+
const watchIdRef = (0, import_react.useRef)(null);
|
|
380
|
+
const stopTracking = (0, import_react.useCallback)(() => {
|
|
381
|
+
if (watchIdRef.current !== null && typeof navigator !== "undefined" && navigator.geolocation) {
|
|
382
|
+
navigator.geolocation.clearWatch(watchIdRef.current);
|
|
383
|
+
}
|
|
384
|
+
watchIdRef.current = null;
|
|
385
|
+
setIsTracking(false);
|
|
386
|
+
}, []);
|
|
387
|
+
const startTracking = (0, import_react.useCallback)(() => {
|
|
388
|
+
if (typeof navigator === "undefined" || !navigator.geolocation) {
|
|
389
|
+
setError({ code: 0, message: "La geolocalizaci\xF3n no est\xE1 disponible en este navegador." });
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
setError(null);
|
|
393
|
+
watchIdRef.current = navigator.geolocation.watchPosition(
|
|
394
|
+
(position) => {
|
|
395
|
+
setLocation({
|
|
396
|
+
lat: position.coords.latitude,
|
|
397
|
+
lon: position.coords.longitude,
|
|
398
|
+
accuracy: position.coords.accuracy
|
|
399
|
+
});
|
|
400
|
+
setIsTracking(true);
|
|
401
|
+
},
|
|
402
|
+
(err) => {
|
|
403
|
+
setError({ code: err.code, message: err.message });
|
|
404
|
+
stopTracking();
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
enableHighAccuracy: options?.enableHighAccuracy ?? true,
|
|
408
|
+
timeout: options?.timeout ?? 12e3,
|
|
409
|
+
maximumAge: options?.maximumAge ?? 0
|
|
410
|
+
}
|
|
411
|
+
);
|
|
412
|
+
}, [options?.enableHighAccuracy, options?.maximumAge, options?.timeout, stopTracking]);
|
|
413
|
+
const toggleTracking = (0, import_react.useCallback)(() => {
|
|
414
|
+
if (isTracking) {
|
|
415
|
+
stopTracking();
|
|
416
|
+
} else {
|
|
417
|
+
startTracking();
|
|
418
|
+
}
|
|
419
|
+
}, [isTracking, startTracking, stopTracking]);
|
|
420
|
+
const clearError = (0, import_react.useCallback)(() => setError(null), []);
|
|
421
|
+
(0, import_react.useEffect)(() => {
|
|
422
|
+
return () => {
|
|
423
|
+
stopTracking();
|
|
424
|
+
};
|
|
425
|
+
}, [stopTracking]);
|
|
426
|
+
return {
|
|
427
|
+
isTracking,
|
|
428
|
+
location,
|
|
429
|
+
error,
|
|
430
|
+
startTracking,
|
|
431
|
+
stopTracking,
|
|
432
|
+
toggleTracking,
|
|
433
|
+
clearError
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// src/react/map/map-utils.ts
|
|
438
|
+
var import_leaflet2 = __toESM(require("leaflet"));
|
|
349
439
|
var POPUP_STYLE_ID = "zenit-leaflet-popup-styles";
|
|
350
|
-
var
|
|
351
|
-
var
|
|
440
|
+
var POPUP_EXCLUDED_KEYS = /* @__PURE__ */ new Set(["geom", "geometry", "_private"]);
|
|
441
|
+
var POPUP_HEADER_KEYS = ["nombre", "name", "title", "titulo"];
|
|
442
|
+
var DESKTOP_POPUP_DIMENSIONS = { maxWidth: 360, minWidth: 280, maxHeight: 520 };
|
|
443
|
+
var MOBILE_POPUP_DIMENSIONS = { maxWidth: 300, minWidth: 240, maxHeight: 420 };
|
|
352
444
|
var ZENIT_LEAFLET_POPUP_STYLES = `
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
/* Main popup wrapper */
|
|
356
|
-
.zenit-leaflet-popup .leaflet-popup-content-wrapper {
|
|
445
|
+
.custom-leaflet-popup .leaflet-popup-content-wrapper {
|
|
357
446
|
border-radius: 12px;
|
|
358
|
-
box-shadow:
|
|
359
|
-
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
360
|
-
0 2px 4px -2px rgba(0, 0, 0, 0.1),
|
|
361
|
-
0 0 0 1px rgba(0, 0, 0, 0.05);
|
|
362
447
|
padding: 0;
|
|
363
448
|
background: #ffffff;
|
|
364
|
-
|
|
449
|
+
box-shadow: 0 12px 24px rgba(15, 23, 42, 0.18);
|
|
450
|
+
border: 1px solid rgba(15, 23, 42, 0.08);
|
|
365
451
|
}
|
|
366
452
|
|
|
367
|
-
|
|
368
|
-
.zenit-leaflet-popup .leaflet-popup-content {
|
|
453
|
+
.custom-leaflet-popup .leaflet-popup-content {
|
|
369
454
|
margin: 0;
|
|
370
|
-
padding:
|
|
455
|
+
padding: 12px 14px;
|
|
371
456
|
font-size: 13px;
|
|
372
|
-
line-height: 1.5;
|
|
373
|
-
color: #374151;
|
|
374
|
-
min-width: 100%;
|
|
375
|
-
overflow-y: auto;
|
|
376
|
-
overflow-x: hidden;
|
|
377
|
-
scrollbar-width: thin;
|
|
378
|
-
scrollbar-color: rgba(156, 163, 175, 0.5) transparent;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/* Popup tip/arrow shadow */
|
|
382
|
-
.zenit-leaflet-popup .leaflet-popup-tip-container {
|
|
383
|
-
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
.zenit-leaflet-popup .leaflet-popup-tip {
|
|
387
|
-
background: #ffffff;
|
|
388
|
-
box-shadow: none;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/* Close button styling */
|
|
392
|
-
.zenit-leaflet-popup .leaflet-popup-close-button {
|
|
393
|
-
color: #9ca3af;
|
|
394
|
-
font-size: 18px;
|
|
395
|
-
font-weight: 400;
|
|
396
|
-
width: 28px;
|
|
397
|
-
height: 28px;
|
|
398
|
-
padding: 0;
|
|
399
|
-
margin: 8px 8px 0 0;
|
|
400
|
-
display: flex;
|
|
401
|
-
align-items: center;
|
|
402
|
-
justify-content: center;
|
|
403
|
-
border-radius: 6px;
|
|
404
|
-
transition: all 0.15s ease;
|
|
405
|
-
z-index: 10;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
.zenit-leaflet-popup .leaflet-popup-close-button:hover {
|
|
409
|
-
color: #374151;
|
|
410
|
-
background-color: #f3f4f6;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
.zenit-leaflet-popup .leaflet-popup-close-button:active {
|
|
414
|
-
background-color: #e5e7eb;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
/* Main card container */
|
|
418
|
-
.zenit-popup-card {
|
|
419
|
-
display: flex;
|
|
420
|
-
flex-direction: column;
|
|
421
|
-
gap: 0;
|
|
422
|
-
padding: 16px;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
/* Individual row styling with subtle separator */
|
|
426
|
-
.zenit-popup-row {
|
|
427
|
-
display: flex;
|
|
428
|
-
flex-direction: column;
|
|
429
|
-
gap: 2px;
|
|
430
|
-
padding: 10px 0;
|
|
431
|
-
border-bottom: 1px solid #f3f4f6;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
.zenit-popup-row:first-child {
|
|
435
|
-
padding-top: 0;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
.zenit-popup-row:last-child {
|
|
439
|
-
border-bottom: none;
|
|
440
|
-
padding-bottom: 0;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
/* Label styling - small, gray, uppercase */
|
|
444
|
-
.zenit-popup-label {
|
|
445
|
-
font-size: 10px;
|
|
446
|
-
font-weight: 500;
|
|
447
|
-
color: #9ca3af;
|
|
448
|
-
text-transform: uppercase;
|
|
449
|
-
letter-spacing: 0.05em;
|
|
450
457
|
line-height: 1.4;
|
|
458
|
+
color: #0f172a;
|
|
459
|
+
max-height: min(70vh, 520px);
|
|
460
|
+
overflow: auto;
|
|
461
|
+
scrollbar-width: thin;
|
|
462
|
+
scrollbar-color: rgba(148, 163, 184, 0.6) transparent;
|
|
451
463
|
}
|
|
452
464
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
font-size:
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
word-break: break-word;
|
|
460
|
-
line-height: 1.5;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
/* Special styling for description field */
|
|
464
|
-
.zenit-popup-row.zenit-popup-description {
|
|
465
|
-
background-color: #f9fafb;
|
|
466
|
-
margin: 0 -16px;
|
|
467
|
-
padding: 12px 16px;
|
|
468
|
-
border-bottom: 1px solid #e5e7eb;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
.zenit-popup-row.zenit-popup-description:first-child {
|
|
472
|
-
margin-top: 0;
|
|
473
|
-
border-radius: 0;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value {
|
|
477
|
-
font-size: 13px;
|
|
478
|
-
line-height: 1.6;
|
|
479
|
-
color: #374151;
|
|
480
|
-
max-height: 150px;
|
|
481
|
-
overflow-y: auto;
|
|
482
|
-
padding-right: 4px;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/* Preformatted text (JSON objects) */
|
|
486
|
-
.zenit-popup-pre {
|
|
487
|
-
margin: 0;
|
|
488
|
-
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
489
|
-
font-size: 11px;
|
|
490
|
-
white-space: pre-wrap;
|
|
491
|
-
word-break: break-word;
|
|
492
|
-
color: #4b5563;
|
|
493
|
-
background-color: #f9fafb;
|
|
494
|
-
padding: 8px;
|
|
495
|
-
border-radius: 6px;
|
|
496
|
-
border: 1px solid #e5e7eb;
|
|
465
|
+
.custom-leaflet-popup .leaflet-popup-close-button {
|
|
466
|
+
color: #64748b;
|
|
467
|
+
font-size: 16px;
|
|
468
|
+
padding: 6px 8px;
|
|
469
|
+
border-radius: 8px;
|
|
470
|
+
transition: background-color 0.15s ease, color 0.15s ease;
|
|
497
471
|
}
|
|
498
472
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
color: #9ca3af;
|
|
503
|
-
font-style: italic;
|
|
504
|
-
text-align: center;
|
|
505
|
-
padding: 20px 0;
|
|
473
|
+
.custom-leaflet-popup .leaflet-popup-close-button:hover {
|
|
474
|
+
color: #0f172a;
|
|
475
|
+
background: rgba(148, 163, 184, 0.2);
|
|
506
476
|
}
|
|
507
477
|
|
|
508
|
-
|
|
509
|
-
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar {
|
|
478
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar {
|
|
510
479
|
width: 6px;
|
|
511
480
|
}
|
|
512
481
|
|
|
513
|
-
.
|
|
514
|
-
background:
|
|
482
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb {
|
|
483
|
+
background: rgba(148, 163, 184, 0.5);
|
|
484
|
+
border-radius: 999px;
|
|
515
485
|
}
|
|
516
486
|
|
|
517
|
-
.
|
|
518
|
-
background-color: rgba(156, 163, 175, 0.4);
|
|
519
|
-
border-radius: 3px;
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb:hover {
|
|
523
|
-
background-color: rgba(107, 114, 128, 0.6);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
/* Scrollbar for description field */
|
|
527
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar {
|
|
528
|
-
width: 4px;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar-track {
|
|
487
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-track {
|
|
532
488
|
background: transparent;
|
|
533
489
|
}
|
|
534
490
|
|
|
535
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar-thumb {
|
|
536
|
-
background-color: rgba(156, 163, 175, 0.4);
|
|
537
|
-
border-radius: 2px;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
/* ===== Responsive: Mobile (<640px) ===== */
|
|
541
491
|
@media (max-width: 640px) {
|
|
542
|
-
.
|
|
543
|
-
border-radius: 10px;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
.zenit-leaflet-popup .leaflet-popup-close-button {
|
|
547
|
-
width: 26px;
|
|
548
|
-
height: 26px;
|
|
549
|
-
font-size: 16px;
|
|
550
|
-
margin: 6px 6px 0 0;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
.zenit-popup-card {
|
|
554
|
-
padding: 12px;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
.zenit-popup-row {
|
|
558
|
-
padding: 8px 0;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
.zenit-popup-label {
|
|
562
|
-
font-size: 9px;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
.zenit-popup-value {
|
|
492
|
+
.custom-leaflet-popup .leaflet-popup-content {
|
|
566
493
|
font-size: 12px;
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
.zenit-popup-row.zenit-popup-description {
|
|
570
|
-
margin: 0 -12px;
|
|
571
494
|
padding: 10px 12px;
|
|
495
|
+
max-height: min(65vh, 420px);
|
|
572
496
|
}
|
|
573
497
|
|
|
574
|
-
.
|
|
575
|
-
font-size:
|
|
576
|
-
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
.zenit-popup-pre {
|
|
580
|
-
font-size: 10px;
|
|
581
|
-
padding: 6px;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
.zenit-popup-empty {
|
|
585
|
-
font-size: 12px;
|
|
586
|
-
padding: 16px 0;
|
|
498
|
+
.custom-leaflet-popup .leaflet-popup-close-button {
|
|
499
|
+
font-size: 14px;
|
|
500
|
+
padding: 4px 6px;
|
|
587
501
|
}
|
|
588
502
|
}
|
|
589
503
|
|
|
590
|
-
/* ===== Map tooltip styling ===== */
|
|
591
504
|
.zenit-map-tooltip {
|
|
592
505
|
background-color: rgba(31, 41, 55, 0.95);
|
|
593
506
|
border: none;
|
|
@@ -602,7 +515,23 @@ var ZENIT_LEAFLET_POPUP_STYLES = `
|
|
|
602
515
|
.zenit-map-tooltip::before {
|
|
603
516
|
border-top-color: rgba(31, 41, 55, 0.95);
|
|
604
517
|
}
|
|
518
|
+
|
|
519
|
+
.polygon-label-tooltip {
|
|
520
|
+
background: rgba(15, 23, 42, 0.92);
|
|
521
|
+
border: none;
|
|
522
|
+
border-radius: 6px;
|
|
523
|
+
color: #f8fafc;
|
|
524
|
+
font-weight: 600;
|
|
525
|
+
font-size: 12px;
|
|
526
|
+
padding: 4px 8px;
|
|
527
|
+
}
|
|
605
528
|
`;
|
|
529
|
+
function clampNumber2(value, min, max) {
|
|
530
|
+
return Math.min(max, Math.max(min, value));
|
|
531
|
+
}
|
|
532
|
+
function clampOpacity4(value) {
|
|
533
|
+
return clampNumber2(value, 0, 1);
|
|
534
|
+
}
|
|
606
535
|
function ensurePopupStyles() {
|
|
607
536
|
if (typeof document === "undefined") return;
|
|
608
537
|
if (document.getElementById(POPUP_STYLE_ID)) return;
|
|
@@ -612,47 +541,52 @@ function ensurePopupStyles() {
|
|
|
612
541
|
document.head.appendChild(styleTag);
|
|
613
542
|
}
|
|
614
543
|
function getPopupDimensions() {
|
|
615
|
-
if (typeof window === "undefined"
|
|
544
|
+
if (typeof window === "undefined") {
|
|
616
545
|
return DESKTOP_POPUP_DIMENSIONS;
|
|
617
546
|
}
|
|
618
|
-
|
|
547
|
+
const isSmallWidth = window.innerWidth < 640;
|
|
548
|
+
const isShortHeight = window.innerHeight < 768;
|
|
549
|
+
const base = isSmallWidth ? MOBILE_POPUP_DIMENSIONS : DESKTOP_POPUP_DIMENSIONS;
|
|
550
|
+
const maxHeight = isShortHeight ? Math.min(base.maxHeight, 360) : base.maxHeight;
|
|
551
|
+
return { ...base, maxHeight };
|
|
619
552
|
}
|
|
620
|
-
function
|
|
621
|
-
|
|
622
|
-
if (typeof value === "string") {
|
|
623
|
-
const trimmed = value.trim();
|
|
624
|
-
return trimmed ? trimmed : null;
|
|
625
|
-
}
|
|
626
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
627
|
-
return String(value);
|
|
628
|
-
}
|
|
629
|
-
return null;
|
|
630
|
-
}
|
|
631
|
-
function extractDescriptionValue(properties) {
|
|
632
|
-
if (!properties) return null;
|
|
633
|
-
const matches = Object.entries(properties).find(
|
|
634
|
-
([key]) => DESCRIPTION_KEYS.has(key.toLowerCase())
|
|
635
|
-
);
|
|
636
|
-
if (!matches) return null;
|
|
637
|
-
return normalizeDescriptionValue(matches[1]);
|
|
553
|
+
function escapeHtml(value) {
|
|
554
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
638
555
|
}
|
|
639
|
-
function
|
|
640
|
-
|
|
641
|
-
const json = JSON.stringify(value, null, 2);
|
|
642
|
-
if (json !== void 0) return json;
|
|
643
|
-
} catch {
|
|
644
|
-
}
|
|
645
|
-
return String(value);
|
|
556
|
+
function formatLabel(key) {
|
|
557
|
+
return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").trim();
|
|
646
558
|
}
|
|
647
559
|
function renderPopupValue(value) {
|
|
648
|
-
if (value === null || value === void 0)
|
|
649
|
-
|
|
560
|
+
if (value === null || value === void 0) return '<span style="color:#94a3b8;">Sin datos</span>';
|
|
561
|
+
if (value instanceof Date) {
|
|
562
|
+
return escapeHtml(value.toLocaleDateString("es-GT"));
|
|
563
|
+
}
|
|
564
|
+
if (typeof value === "number") {
|
|
565
|
+
return escapeHtml(value.toLocaleString("es-GT"));
|
|
566
|
+
}
|
|
567
|
+
if (typeof value === "string") {
|
|
568
|
+
const trimmed = value.trim();
|
|
569
|
+
if (!trimmed) return '<span style="color:#94a3b8;">Sin datos</span>';
|
|
570
|
+
return escapeHtml(trimmed);
|
|
650
571
|
}
|
|
651
572
|
if (typeof value === "object") {
|
|
652
|
-
|
|
653
|
-
|
|
573
|
+
try {
|
|
574
|
+
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(
|
|
575
|
+
JSON.stringify(value, null, 2)
|
|
576
|
+
)}</pre>`;
|
|
577
|
+
} catch {
|
|
578
|
+
return escapeHtml(String(value));
|
|
579
|
+
}
|
|
654
580
|
}
|
|
655
|
-
return
|
|
581
|
+
return escapeHtml(String(value));
|
|
582
|
+
}
|
|
583
|
+
function extractPopupHeader(properties) {
|
|
584
|
+
const entry = Object.entries(properties).find(([key, value]) => {
|
|
585
|
+
if (typeof value !== "string") return false;
|
|
586
|
+
const normalized = key.trim().toLowerCase();
|
|
587
|
+
return POPUP_HEADER_KEYS.includes(normalized) && value.trim().length > 0;
|
|
588
|
+
});
|
|
589
|
+
return entry ? entry[1].trim() : null;
|
|
656
590
|
}
|
|
657
591
|
function shouldIncludePopupEntry(key, value) {
|
|
658
592
|
if (!key) return false;
|
|
@@ -664,99 +598,480 @@ function shouldIncludePopupEntry(key, value) {
|
|
|
664
598
|
if (typeof value === "string" && !value.trim()) return false;
|
|
665
599
|
return true;
|
|
666
600
|
}
|
|
667
|
-
function isDescriptionKey(key) {
|
|
668
|
-
const normalized = key.trim().toLowerCase();
|
|
669
|
-
return DESCRIPTION_KEYS.has(normalized);
|
|
670
|
-
}
|
|
671
|
-
function formatLabel(key) {
|
|
672
|
-
return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").trim();
|
|
673
|
-
}
|
|
674
601
|
function createPopupContent(properties) {
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
602
|
+
const headerText = extractPopupHeader(properties);
|
|
603
|
+
const entries = Object.entries(properties).filter(([key, value]) => {
|
|
604
|
+
if (!shouldIncludePopupEntry(key, value)) return false;
|
|
605
|
+
if (headerText && POPUP_HEADER_KEYS.includes(key.trim().toLowerCase())) return false;
|
|
606
|
+
return true;
|
|
607
|
+
});
|
|
678
608
|
if (entries.length === 0) {
|
|
679
|
-
return
|
|
609
|
+
return '<div style="padding:8px 0; color:#64748b; text-align:center;">Sin datos disponibles</div>';
|
|
680
610
|
}
|
|
681
|
-
const
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
const [key, value] = descriptionEntry;
|
|
611
|
+
const headerHtml = headerText ? `<div style="font-weight:700; font-size:14px; margin-bottom:8px; color:#0f172a;">${escapeHtml(
|
|
612
|
+
headerText
|
|
613
|
+
)}</div>` : "";
|
|
614
|
+
const rowsHtml = entries.map(([key, value]) => {
|
|
686
615
|
const label = escapeHtml(formatLabel(key));
|
|
687
616
|
const valueHtml = renderPopupValue(value);
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
617
|
+
return `
|
|
618
|
+
<div style="display:grid; grid-template-columns:minmax(90px, 35%) 1fr; gap:8px; padding:6px 0; border-bottom:1px solid #e2e8f0;">
|
|
619
|
+
<div style="font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.04em; color:#64748b;">${label}</div>
|
|
620
|
+
<div style="font-size:13px; color:#0f172a; word-break:break-word;">${valueHtml}</div>
|
|
621
|
+
</div>
|
|
622
|
+
`;
|
|
623
|
+
}).join("");
|
|
624
|
+
return `<div>${headerHtml}${rowsHtml}</div>`;
|
|
625
|
+
}
|
|
626
|
+
function isPolygonType(layerType, geometryType) {
|
|
627
|
+
const candidate = (layerType ?? geometryType ?? "").toLowerCase();
|
|
628
|
+
return candidate === "polygon" || candidate === "multipolygon";
|
|
629
|
+
}
|
|
630
|
+
function calculateZoomBasedOpacity(zoom, baseOpacity, layerType, geometryType) {
|
|
631
|
+
if (!isPolygonType(layerType, geometryType)) return clampOpacity4(baseOpacity);
|
|
632
|
+
const minZoom = 11;
|
|
633
|
+
const maxZoom = 15;
|
|
634
|
+
const minFactor = 0.3;
|
|
635
|
+
if (maxZoom <= minZoom) return clampOpacity4(baseOpacity * minFactor);
|
|
636
|
+
const t = clampNumber2((zoom - minZoom) / (maxZoom - minZoom), 0, 1);
|
|
637
|
+
const factor = 1 - (1 - minFactor) * t;
|
|
638
|
+
return clampOpacity4(baseOpacity * factor);
|
|
639
|
+
}
|
|
640
|
+
function layerStyleToLeaflet(options) {
|
|
641
|
+
const { baseOpacity, zoom, layerStyle, geometryType, layerType } = options;
|
|
642
|
+
const sanitizedOpacity = clampOpacity4(baseOpacity);
|
|
643
|
+
const zoomOpacity = calculateZoomBasedOpacity(zoom, sanitizedOpacity, layerType, geometryType);
|
|
644
|
+
const styleFillOpacity = typeof layerStyle?.fillOpacity === "number" ? clampOpacity4(layerStyle.fillOpacity) : 0.8;
|
|
645
|
+
return {
|
|
646
|
+
color: layerStyle?.color ?? layerStyle?.fillColor ?? "#2563eb",
|
|
647
|
+
weight: layerStyle?.weight ?? 2,
|
|
648
|
+
fillColor: layerStyle?.fillColor ?? layerStyle?.color ?? "#2563eb",
|
|
649
|
+
opacity: clampOpacity4(Math.max(0.35, zoomOpacity * 0.9)),
|
|
650
|
+
fillOpacity: clampOpacity4(zoomOpacity * styleFillOpacity)
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function getRgbFromColor(color) {
|
|
654
|
+
const trimmed = color.trim();
|
|
655
|
+
if (trimmed.startsWith("#")) {
|
|
656
|
+
const hex = trimmed.replace("#", "");
|
|
657
|
+
const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
|
|
658
|
+
if (expanded.length === 6) {
|
|
659
|
+
const r = parseInt(expanded.slice(0, 2), 16);
|
|
660
|
+
const g = parseInt(expanded.slice(2, 4), 16);
|
|
661
|
+
const b = parseInt(expanded.slice(4, 6), 16);
|
|
662
|
+
return { r, g, b };
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
const rgbMatch = trimmed.match(/rgba?\(([^)]+)\)/i);
|
|
666
|
+
if (rgbMatch) {
|
|
667
|
+
const [r, g, b] = rgbMatch[1].split(",").map((value) => parseFloat(value.trim())).slice(0, 3);
|
|
668
|
+
if ([r, g, b].every((value) => Number.isFinite(value))) {
|
|
669
|
+
return { r, g, b };
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
function getLabelTextStyles(color) {
|
|
675
|
+
const rgb = getRgbFromColor(color);
|
|
676
|
+
if (!rgb) {
|
|
677
|
+
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.6)" };
|
|
678
|
+
}
|
|
679
|
+
const luminance = (0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b) / 255;
|
|
680
|
+
if (luminance > 0.6) {
|
|
681
|
+
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.7)" };
|
|
682
|
+
}
|
|
683
|
+
return { color: "#ffffff", shadow: "0 1px 2px rgba(0, 0, 0, 0.4)" };
|
|
684
|
+
}
|
|
685
|
+
function withAlpha(color, alpha) {
|
|
686
|
+
const trimmed = color.trim();
|
|
687
|
+
if (trimmed.startsWith("#")) {
|
|
688
|
+
const hex = trimmed.replace("#", "");
|
|
689
|
+
const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
|
|
690
|
+
if (expanded.length === 6) {
|
|
691
|
+
const r = parseInt(expanded.slice(0, 2), 16);
|
|
692
|
+
const g = parseInt(expanded.slice(2, 4), 16);
|
|
693
|
+
const b = parseInt(expanded.slice(4, 6), 16);
|
|
694
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
if (trimmed.startsWith("rgb(")) {
|
|
698
|
+
const inner = trimmed.slice(4, -1);
|
|
699
|
+
return `rgba(${inner}, ${alpha})`;
|
|
700
|
+
}
|
|
701
|
+
if (trimmed.startsWith("rgba(")) {
|
|
702
|
+
const inner = trimmed.slice(5, -1).split(",").slice(0, 3).map((value) => value.trim());
|
|
703
|
+
return `rgba(${inner.join(", ")}, ${alpha})`;
|
|
704
|
+
}
|
|
705
|
+
return color;
|
|
706
|
+
}
|
|
707
|
+
function createCustomIcon(label, opacity, color) {
|
|
708
|
+
const size = 60;
|
|
709
|
+
const innerSize = 44;
|
|
710
|
+
const textStyles = getLabelTextStyles(color);
|
|
711
|
+
const safeLabel = escapeHtml(label);
|
|
712
|
+
const clampedOpacity = Math.min(1, Math.max(0.92, opacity));
|
|
713
|
+
const innerBackground = withAlpha(color, 0.9);
|
|
714
|
+
return import_leaflet2.default.divIcon({
|
|
715
|
+
className: "zenit-label-marker",
|
|
716
|
+
iconSize: [size, size],
|
|
717
|
+
iconAnchor: [size / 2, size / 2],
|
|
718
|
+
html: `
|
|
719
|
+
<div
|
|
720
|
+
title="${safeLabel}"
|
|
721
|
+
style="
|
|
722
|
+
width:${size}px;
|
|
723
|
+
height:${size}px;
|
|
724
|
+
border-radius:9999px;
|
|
725
|
+
background:rgba(255, 255, 255, 0.95);
|
|
726
|
+
border:3px solid rgba(255, 255, 255, 1);
|
|
727
|
+
display:flex;
|
|
728
|
+
align-items:center;
|
|
729
|
+
justify-content:center;
|
|
730
|
+
opacity:${clampedOpacity};
|
|
731
|
+
box-shadow:0 2px 6px rgba(0, 0, 0, 0.25);
|
|
732
|
+
pointer-events:none;
|
|
733
|
+
"
|
|
734
|
+
>
|
|
735
|
+
<div
|
|
736
|
+
style="
|
|
737
|
+
width:${innerSize}px;
|
|
738
|
+
height:${innerSize}px;
|
|
739
|
+
border-radius:9999px;
|
|
740
|
+
background:${innerBackground};
|
|
741
|
+
display:flex;
|
|
742
|
+
align-items:center;
|
|
743
|
+
justify-content:center;
|
|
744
|
+
box-shadow:inset 0 0 0 1px rgba(15, 23, 42, 0.12);
|
|
745
|
+
"
|
|
746
|
+
>
|
|
747
|
+
<span
|
|
748
|
+
style="
|
|
749
|
+
color:${textStyles.color};
|
|
750
|
+
font-size:20px;
|
|
751
|
+
font-weight:800;
|
|
752
|
+
text-shadow:${textStyles.shadow};
|
|
753
|
+
"
|
|
754
|
+
>
|
|
755
|
+
${safeLabel}
|
|
756
|
+
</span>
|
|
757
|
+
</div>
|
|
692
758
|
</div>
|
|
693
|
-
|
|
759
|
+
`
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
function createLocationIcon() {
|
|
763
|
+
return import_leaflet2.default.divIcon({
|
|
764
|
+
className: "zenit-location-marker",
|
|
765
|
+
iconSize: [18, 18],
|
|
766
|
+
iconAnchor: [9, 9],
|
|
767
|
+
html: `
|
|
768
|
+
<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>
|
|
769
|
+
`
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// src/react/map/location-control.tsx
|
|
774
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
775
|
+
var LOCATION_STYLE_ID = "zenit-location-control-styles";
|
|
776
|
+
var LOCATION_STYLES = `
|
|
777
|
+
.zenit-location-control {
|
|
778
|
+
display: flex;
|
|
779
|
+
flex-direction: column;
|
|
780
|
+
gap: 8px;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.zenit-location-button {
|
|
784
|
+
width: 42px;
|
|
785
|
+
height: 42px;
|
|
786
|
+
border-radius: 12px;
|
|
787
|
+
border: none;
|
|
788
|
+
background: #ffffff;
|
|
789
|
+
color: #0f172a;
|
|
790
|
+
box-shadow: 0 8px 18px rgba(15, 23, 42, 0.2);
|
|
791
|
+
display: inline-flex;
|
|
792
|
+
align-items: center;
|
|
793
|
+
justify-content: center;
|
|
794
|
+
cursor: pointer;
|
|
795
|
+
position: relative;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
.zenit-location-button.zenit-location-button--tracking {
|
|
799
|
+
animation: zenitLocationPulse 1.8s infinite;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
.zenit-location-button:hover {
|
|
803
|
+
background: #f8fafc;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.zenit-location-badge {
|
|
807
|
+
position: absolute;
|
|
808
|
+
top: -6px;
|
|
809
|
+
right: -6px;
|
|
810
|
+
width: 18px;
|
|
811
|
+
height: 18px;
|
|
812
|
+
border-radius: 999px;
|
|
813
|
+
background: #ef4444;
|
|
814
|
+
color: #fff;
|
|
815
|
+
font-size: 11px;
|
|
816
|
+
font-weight: 700;
|
|
817
|
+
display: inline-flex;
|
|
818
|
+
align-items: center;
|
|
819
|
+
justify-content: center;
|
|
820
|
+
box-shadow: 0 4px 10px rgba(239, 68, 68, 0.35);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
.zenit-location-error {
|
|
824
|
+
background: rgba(15, 23, 42, 0.92);
|
|
825
|
+
color: #f8fafc;
|
|
826
|
+
border-radius: 10px;
|
|
827
|
+
padding: 8px 10px;
|
|
828
|
+
font-size: 12px;
|
|
829
|
+
max-width: 200px;
|
|
830
|
+
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.3);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
@keyframes zenitLocationPulse {
|
|
834
|
+
0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.35); }
|
|
835
|
+
70% { box-shadow: 0 0 0 12px rgba(16, 185, 129, 0); }
|
|
836
|
+
100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
|
|
837
|
+
}
|
|
838
|
+
`;
|
|
839
|
+
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: [
|
|
840
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "3" }),
|
|
841
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "2", x2: "12", y2: "5" }),
|
|
842
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "19", x2: "12", y2: "22" }),
|
|
843
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "2", y1: "12", x2: "5", y2: "12" }),
|
|
844
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "19", y1: "12", x2: "22", y2: "12" })
|
|
845
|
+
] });
|
|
846
|
+
var LocationControl = ({ position = "bottomleft", zoom = 16 }) => {
|
|
847
|
+
const map = (0, import_react_leaflet2.useMap)();
|
|
848
|
+
const controlRef = (0, import_react2.useRef)(null);
|
|
849
|
+
const hasCenteredRef = (0, import_react2.useRef)(false);
|
|
850
|
+
const { isTracking, location, error, toggleTracking, clearError } = useGeolocation();
|
|
851
|
+
(0, import_react2.useEffect)(() => {
|
|
852
|
+
if (typeof document === "undefined") return;
|
|
853
|
+
if (document.getElementById(LOCATION_STYLE_ID)) return;
|
|
854
|
+
const styleTag = document.createElement("style");
|
|
855
|
+
styleTag.id = LOCATION_STYLE_ID;
|
|
856
|
+
styleTag.textContent = LOCATION_STYLES;
|
|
857
|
+
document.head.appendChild(styleTag);
|
|
858
|
+
}, []);
|
|
859
|
+
(0, import_react2.useEffect)(() => {
|
|
860
|
+
const control = import_leaflet3.default.control({ position });
|
|
861
|
+
control.onAdd = () => {
|
|
862
|
+
const container = import_leaflet3.default.DomUtil.create("div", "zenit-location-control");
|
|
863
|
+
import_leaflet3.default.DomEvent.disableClickPropagation(container);
|
|
864
|
+
controlRef.current = container;
|
|
865
|
+
return container;
|
|
866
|
+
};
|
|
867
|
+
control.addTo(map);
|
|
868
|
+
return () => {
|
|
869
|
+
control.remove();
|
|
870
|
+
controlRef.current = null;
|
|
871
|
+
};
|
|
872
|
+
}, [map, position]);
|
|
873
|
+
(0, import_react2.useEffect)(() => {
|
|
874
|
+
if (!location || !isTracking) return;
|
|
875
|
+
if (hasCenteredRef.current) return;
|
|
876
|
+
hasCenteredRef.current = true;
|
|
877
|
+
map.flyTo([location.lat, location.lon], zoom, { animate: true });
|
|
878
|
+
}, [isTracking, location, map, zoom]);
|
|
879
|
+
const markerIcon = (0, import_react2.useMemo)(() => createLocationIcon(), []);
|
|
880
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
881
|
+
controlRef.current && (0, import_react_dom.createPortal)(
|
|
882
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
883
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
884
|
+
"button",
|
|
885
|
+
{
|
|
886
|
+
type: "button",
|
|
887
|
+
className: `zenit-location-button${isTracking ? " zenit-location-button--tracking" : ""}`,
|
|
888
|
+
onClick: () => {
|
|
889
|
+
if (error) {
|
|
890
|
+
clearError();
|
|
891
|
+
}
|
|
892
|
+
toggleTracking();
|
|
893
|
+
},
|
|
894
|
+
"aria-label": isTracking ? "Detener ubicaci\xF3n" : "Mostrar mi ubicaci\xF3n",
|
|
895
|
+
children: [
|
|
896
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LocateIcon, {}),
|
|
897
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "zenit-location-badge", children: "!" })
|
|
898
|
+
]
|
|
899
|
+
}
|
|
900
|
+
),
|
|
901
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "zenit-location-error", children: error.message || "No se pudo acceder a tu ubicaci\xF3n." })
|
|
902
|
+
] }),
|
|
903
|
+
controlRef.current
|
|
904
|
+
),
|
|
905
|
+
location && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
906
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_leaflet2.Marker, { position: [location.lat, location.lon], icon: markerIcon }),
|
|
907
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
908
|
+
import_react_leaflet2.Circle,
|
|
909
|
+
{
|
|
910
|
+
center: [location.lat, location.lon],
|
|
911
|
+
radius: location.accuracy,
|
|
912
|
+
pathOptions: { color: "#2563eb", fillColor: "#2563eb", fillOpacity: 0.15 }
|
|
913
|
+
}
|
|
914
|
+
)
|
|
915
|
+
] })
|
|
916
|
+
] });
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
// src/react/map/map-handlers.tsx
|
|
920
|
+
var import_react3 = require("react");
|
|
921
|
+
var import_react_leaflet3 = require("react-leaflet");
|
|
922
|
+
function computeBBoxFromGeojson(geojson) {
|
|
923
|
+
if (!geojson || !Array.isArray(geojson.features)) return null;
|
|
924
|
+
const coords = [];
|
|
925
|
+
const collect = (candidate) => {
|
|
926
|
+
if (!Array.isArray(candidate)) return;
|
|
927
|
+
if (candidate.length === 2 && typeof candidate[0] === "number" && typeof candidate[1] === "number" && Number.isFinite(candidate[0]) && Number.isFinite(candidate[1])) {
|
|
928
|
+
coords.push([candidate[0], candidate[1]]);
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
candidate.forEach((item) => collect(item));
|
|
932
|
+
};
|
|
933
|
+
geojson.features.forEach((feature) => {
|
|
934
|
+
collect(feature.geometry?.coordinates);
|
|
935
|
+
});
|
|
936
|
+
if (coords.length === 0) return null;
|
|
937
|
+
const [firstLon, firstLat] = coords[0];
|
|
938
|
+
const bbox = { minLon: firstLon, minLat: firstLat, maxLon: firstLon, maxLat: firstLat };
|
|
939
|
+
coords.forEach(([lon, lat]) => {
|
|
940
|
+
bbox.minLon = Math.min(bbox.minLon, lon);
|
|
941
|
+
bbox.minLat = Math.min(bbox.minLat, lat);
|
|
942
|
+
bbox.maxLon = Math.max(bbox.maxLon, lon);
|
|
943
|
+
bbox.maxLat = Math.max(bbox.maxLat, lat);
|
|
944
|
+
});
|
|
945
|
+
return bbox;
|
|
946
|
+
}
|
|
947
|
+
function mergeBBoxes(bboxes) {
|
|
948
|
+
const valid = bboxes.filter((bbox) => !!bbox);
|
|
949
|
+
if (valid.length === 0) return null;
|
|
950
|
+
const first = valid[0];
|
|
951
|
+
return valid.slice(1).reduce(
|
|
952
|
+
(acc, bbox) => ({
|
|
953
|
+
minLon: Math.min(acc.minLon, bbox.minLon),
|
|
954
|
+
minLat: Math.min(acc.minLat, bbox.minLat),
|
|
955
|
+
maxLon: Math.max(acc.maxLon, bbox.maxLon),
|
|
956
|
+
maxLat: Math.max(acc.maxLat, bbox.maxLat)
|
|
957
|
+
}),
|
|
958
|
+
{ ...first }
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
var BBoxZoomHandler = ({
|
|
962
|
+
bbox,
|
|
963
|
+
geojson,
|
|
964
|
+
autoGeojson = [],
|
|
965
|
+
enabled = true
|
|
966
|
+
}) => {
|
|
967
|
+
const map = (0, import_react_leaflet3.useMap)();
|
|
968
|
+
const lastAppliedBBox = (0, import_react3.useRef)(null);
|
|
969
|
+
const lastUserInteracted = (0, import_react3.useRef)(false);
|
|
970
|
+
(0, import_react3.useEffect)(() => {
|
|
971
|
+
const handleInteraction = () => {
|
|
972
|
+
lastUserInteracted.current = true;
|
|
973
|
+
};
|
|
974
|
+
map.on("dragstart", handleInteraction);
|
|
975
|
+
map.on("zoomstart", handleInteraction);
|
|
976
|
+
return () => {
|
|
977
|
+
map.off("dragstart", handleInteraction);
|
|
978
|
+
map.off("zoomstart", handleInteraction);
|
|
979
|
+
};
|
|
980
|
+
}, [map]);
|
|
981
|
+
(0, import_react3.useEffect)(() => {
|
|
982
|
+
if (!enabled) return;
|
|
983
|
+
let resolvedBBox = bbox ?? null;
|
|
984
|
+
if (!resolvedBBox && geojson) {
|
|
985
|
+
resolvedBBox = computeBBoxFromGeojson(geojson);
|
|
986
|
+
}
|
|
987
|
+
if (!resolvedBBox && autoGeojson.length > 0) {
|
|
988
|
+
const bboxes = autoGeojson.map((collection) => computeBBoxFromGeojson(collection));
|
|
989
|
+
resolvedBBox = mergeBBoxes(bboxes);
|
|
990
|
+
}
|
|
991
|
+
if (!resolvedBBox) return;
|
|
992
|
+
const serialized = JSON.stringify(resolvedBBox);
|
|
993
|
+
if (lastAppliedBBox.current === serialized) return;
|
|
994
|
+
if (lastUserInteracted.current && !bbox && !geojson) {
|
|
995
|
+
lastUserInteracted.current = false;
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
const bounds = [
|
|
999
|
+
[resolvedBBox.minLat, resolvedBBox.minLon],
|
|
1000
|
+
[resolvedBBox.maxLat, resolvedBBox.maxLon]
|
|
1001
|
+
];
|
|
1002
|
+
map.fitBounds(bounds, { padding: [12, 12] });
|
|
1003
|
+
lastAppliedBBox.current = serialized;
|
|
1004
|
+
}, [autoGeojson, bbox, enabled, geojson, map]);
|
|
1005
|
+
return null;
|
|
1006
|
+
};
|
|
1007
|
+
var ZoomBasedOpacityHandler = ({ onZoomChange }) => {
|
|
1008
|
+
const map = (0, import_react_leaflet3.useMap)();
|
|
1009
|
+
(0, import_react3.useEffect)(() => {
|
|
1010
|
+
const handleZoom = () => {
|
|
1011
|
+
onZoomChange(map.getZoom());
|
|
1012
|
+
};
|
|
1013
|
+
map.on("zoomend", handleZoom);
|
|
1014
|
+
handleZoom();
|
|
1015
|
+
return () => {
|
|
1016
|
+
map.off("zoomend", handleZoom);
|
|
1017
|
+
};
|
|
1018
|
+
}, [map, onZoomChange]);
|
|
1019
|
+
return null;
|
|
1020
|
+
};
|
|
1021
|
+
var MapInstanceBridge = ({ onReady }) => {
|
|
1022
|
+
const map = (0, import_react_leaflet3.useMap)();
|
|
1023
|
+
(0, import_react3.useEffect)(() => {
|
|
1024
|
+
onReady(map);
|
|
1025
|
+
}, [map, onReady]);
|
|
1026
|
+
return null;
|
|
1027
|
+
};
|
|
1028
|
+
|
|
1029
|
+
// src/react/ZenitMap.tsx
|
|
1030
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1031
|
+
var DEFAULT_CENTER = [0, 0];
|
|
1032
|
+
var DEFAULT_ZOOM = 3;
|
|
1033
|
+
var LABELS_PANE_NAME = "zenit-labels-pane";
|
|
1034
|
+
function isRecord(value) {
|
|
1035
|
+
return typeof value === "object" && value !== null;
|
|
1036
|
+
}
|
|
1037
|
+
function isGeoJsonFeatureCollection(value) {
|
|
1038
|
+
if (!isRecord(value)) return false;
|
|
1039
|
+
const features = value.features;
|
|
1040
|
+
if (!Array.isArray(features)) return false;
|
|
1041
|
+
const type = value.type;
|
|
1042
|
+
return type === void 0 || type === "FeatureCollection";
|
|
1043
|
+
}
|
|
1044
|
+
function extractGeoJsonFeatureCollection(value) {
|
|
1045
|
+
if (isRecord(value) && "data" in value) {
|
|
1046
|
+
const data = value.data;
|
|
1047
|
+
return isGeoJsonFeatureCollection(data) ? data : null;
|
|
694
1048
|
}
|
|
695
|
-
|
|
696
|
-
const label = escapeHtml(formatLabel(key));
|
|
697
|
-
const valueHtml = renderPopupValue(value);
|
|
698
|
-
return `
|
|
699
|
-
<div class="zenit-popup-row">
|
|
700
|
-
<div class="zenit-popup-label">${label}</div>
|
|
701
|
-
<div class="zenit-popup-value">${valueHtml}</div>
|
|
702
|
-
</div>
|
|
703
|
-
`;
|
|
704
|
-
}).join("");
|
|
705
|
-
return `<div class="zenit-popup-card">${rowsHtml}</div>`;
|
|
1049
|
+
return isGeoJsonFeatureCollection(value) ? value : null;
|
|
706
1050
|
}
|
|
707
|
-
function
|
|
708
|
-
const
|
|
709
|
-
if (
|
|
710
|
-
|
|
711
|
-
const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
|
|
712
|
-
if (expanded.length === 6) {
|
|
713
|
-
const r = parseInt(expanded.slice(0, 2), 16);
|
|
714
|
-
const g = parseInt(expanded.slice(2, 4), 16);
|
|
715
|
-
const b = parseInt(expanded.slice(4, 6), 16);
|
|
716
|
-
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
if (trimmed.startsWith("rgb(")) {
|
|
720
|
-
const inner = trimmed.slice(4, -1);
|
|
721
|
-
return `rgba(${inner}, ${alpha})`;
|
|
722
|
-
}
|
|
723
|
-
if (trimmed.startsWith("rgba(")) {
|
|
724
|
-
const inner = trimmed.slice(5, -1).split(",").slice(0, 3).map((value) => value.trim());
|
|
725
|
-
return `rgba(${inner.join(", ")}, ${alpha})`;
|
|
726
|
-
}
|
|
727
|
-
return color;
|
|
1051
|
+
function getFeatureLayerId(feature) {
|
|
1052
|
+
const layerId = feature?.properties?.__zenit_layerId ?? feature?.properties?.layerId ?? feature?.properties?.layer_id;
|
|
1053
|
+
if (layerId === void 0 || layerId === null) return null;
|
|
1054
|
+
return layerId;
|
|
728
1055
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
if (
|
|
732
|
-
|
|
733
|
-
const
|
|
734
|
-
|
|
735
|
-
const r = parseInt(expanded.slice(0, 2), 16);
|
|
736
|
-
const g = parseInt(expanded.slice(2, 4), 16);
|
|
737
|
-
const b = parseInt(expanded.slice(4, 6), 16);
|
|
738
|
-
return { r, g, b };
|
|
739
|
-
}
|
|
1056
|
+
var DESCRIPTION_KEYS = /* @__PURE__ */ new Set(["descripcion", "description"]);
|
|
1057
|
+
function normalizeDescriptionValue(value) {
|
|
1058
|
+
if (value === void 0 || value === null) return null;
|
|
1059
|
+
if (typeof value === "string") {
|
|
1060
|
+
const trimmed = value.trim();
|
|
1061
|
+
return trimmed ? trimmed : null;
|
|
740
1062
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
const [r, g, b] = rgbMatch[1].split(",").map((value) => parseFloat(value.trim())).slice(0, 3);
|
|
744
|
-
if ([r, g, b].every((value) => Number.isFinite(value))) {
|
|
745
|
-
return { r, g, b };
|
|
746
|
-
}
|
|
1063
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
1064
|
+
return String(value);
|
|
747
1065
|
}
|
|
748
1066
|
return null;
|
|
749
1067
|
}
|
|
750
|
-
function
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.7)" };
|
|
758
|
-
}
|
|
759
|
-
return { color: "#ffffff", shadow: "0 1px 2px rgba(0, 0, 0, 0.4)" };
|
|
1068
|
+
function extractDescriptionValue(properties) {
|
|
1069
|
+
if (!properties) return null;
|
|
1070
|
+
const matches = Object.entries(properties).find(
|
|
1071
|
+
([key]) => DESCRIPTION_KEYS.has(key.toLowerCase())
|
|
1072
|
+
);
|
|
1073
|
+
if (!matches) return null;
|
|
1074
|
+
return normalizeDescriptionValue(matches[1]);
|
|
760
1075
|
}
|
|
761
1076
|
function getFeatureStyleOverrides(feature) {
|
|
762
1077
|
const candidate = feature?.properties?._style;
|
|
@@ -775,25 +1090,6 @@ function buildFeaturePopupHtml(feature) {
|
|
|
775
1090
|
const rendered = createPopupContent(properties);
|
|
776
1091
|
return rendered ? rendered : null;
|
|
777
1092
|
}
|
|
778
|
-
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
779
|
-
function getGeometryType(feature) {
|
|
780
|
-
const t = feature?.geometry?.type;
|
|
781
|
-
return typeof t === "string" ? t : null;
|
|
782
|
-
}
|
|
783
|
-
function isPointGeometry(feature) {
|
|
784
|
-
const geometryType = getGeometryType(feature);
|
|
785
|
-
return geometryType !== null && POINT_GEOMETRY_TYPES.has(geometryType);
|
|
786
|
-
}
|
|
787
|
-
function isNonPointGeometry(feature) {
|
|
788
|
-
const geometryType = getGeometryType(feature);
|
|
789
|
-
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
790
|
-
}
|
|
791
|
-
function buildFeatureCollection(features) {
|
|
792
|
-
return {
|
|
793
|
-
type: "FeatureCollection",
|
|
794
|
-
features
|
|
795
|
-
};
|
|
796
|
-
}
|
|
797
1093
|
function pickIntersectFeature(baseFeature, candidates) {
|
|
798
1094
|
if (!Array.isArray(candidates) || candidates.length === 0) return null;
|
|
799
1095
|
const baseId = baseFeature?.id;
|
|
@@ -820,81 +1116,7 @@ function normalizeCenterTuple(center) {
|
|
|
820
1116
|
}
|
|
821
1117
|
return null;
|
|
822
1118
|
}
|
|
823
|
-
var
|
|
824
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
825
|
-
const lastAppliedBBox = (0, import_react.useRef)(null);
|
|
826
|
-
(0, import_react.useEffect)(() => {
|
|
827
|
-
const targetBBox = bbox;
|
|
828
|
-
if (!targetBBox) return;
|
|
829
|
-
const serialized = JSON.stringify(targetBBox);
|
|
830
|
-
if (lastAppliedBBox.current === serialized) return;
|
|
831
|
-
const bounds = [
|
|
832
|
-
[targetBBox.minLat, targetBBox.minLon],
|
|
833
|
-
[targetBBox.maxLat, targetBBox.maxLon]
|
|
834
|
-
];
|
|
835
|
-
mapInstance.fitBounds(bounds, { padding: [12, 12] });
|
|
836
|
-
lastAppliedBBox.current = serialized;
|
|
837
|
-
}, [bbox, mapInstance]);
|
|
838
|
-
return null;
|
|
839
|
-
};
|
|
840
|
-
var AutoFitToBounds = ({
|
|
841
|
-
bbox,
|
|
842
|
-
enabled = true
|
|
843
|
-
}) => {
|
|
844
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
845
|
-
const lastAutoBBoxApplied = (0, import_react.useRef)(null);
|
|
846
|
-
const lastUserInteracted = (0, import_react.useRef)(false);
|
|
847
|
-
(0, import_react.useEffect)(() => {
|
|
848
|
-
if (!enabled) return;
|
|
849
|
-
const handleInteraction = () => {
|
|
850
|
-
lastUserInteracted.current = true;
|
|
851
|
-
};
|
|
852
|
-
mapInstance.on("dragstart", handleInteraction);
|
|
853
|
-
mapInstance.on("zoomstart", handleInteraction);
|
|
854
|
-
return () => {
|
|
855
|
-
mapInstance.off("dragstart", handleInteraction);
|
|
856
|
-
mapInstance.off("zoomstart", handleInteraction);
|
|
857
|
-
};
|
|
858
|
-
}, [enabled, mapInstance]);
|
|
859
|
-
(0, import_react.useEffect)(() => {
|
|
860
|
-
if (!enabled) return;
|
|
861
|
-
if (!bbox) return;
|
|
862
|
-
const serialized = JSON.stringify(bbox);
|
|
863
|
-
if (lastAutoBBoxApplied.current === serialized) return;
|
|
864
|
-
if (lastUserInteracted.current) {
|
|
865
|
-
lastUserInteracted.current = false;
|
|
866
|
-
}
|
|
867
|
-
const bounds = [
|
|
868
|
-
[bbox.minLat, bbox.minLon],
|
|
869
|
-
[bbox.maxLat, bbox.maxLon]
|
|
870
|
-
];
|
|
871
|
-
mapInstance.fitBounds(bounds, { padding: [12, 12] });
|
|
872
|
-
lastAutoBBoxApplied.current = serialized;
|
|
873
|
-
}, [bbox, enabled, mapInstance]);
|
|
874
|
-
return null;
|
|
875
|
-
};
|
|
876
|
-
var ZoomBasedOpacityHandler = ({ onZoomChange }) => {
|
|
877
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
878
|
-
(0, import_react.useEffect)(() => {
|
|
879
|
-
const handleZoom = () => {
|
|
880
|
-
onZoomChange(mapInstance.getZoom());
|
|
881
|
-
};
|
|
882
|
-
mapInstance.on("zoomend", handleZoom);
|
|
883
|
-
handleZoom();
|
|
884
|
-
return () => {
|
|
885
|
-
mapInstance.off("zoomend", handleZoom);
|
|
886
|
-
};
|
|
887
|
-
}, [mapInstance, onZoomChange]);
|
|
888
|
-
return null;
|
|
889
|
-
};
|
|
890
|
-
var MapInstanceBridge = ({ onReady }) => {
|
|
891
|
-
const mapInstance = (0, import_react_leaflet.useMap)();
|
|
892
|
-
(0, import_react.useEffect)(() => {
|
|
893
|
-
onReady(mapInstance);
|
|
894
|
-
}, [mapInstance, onReady]);
|
|
895
|
-
return null;
|
|
896
|
-
};
|
|
897
|
-
var ZenitMap = (0, import_react.forwardRef)(({
|
|
1119
|
+
var ZenitMap = (0, import_react4.forwardRef)(({
|
|
898
1120
|
client,
|
|
899
1121
|
mapId,
|
|
900
1122
|
height = "500px",
|
|
@@ -919,20 +1141,21 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
919
1141
|
onZoomChange,
|
|
920
1142
|
onMapReady
|
|
921
1143
|
}, ref) => {
|
|
922
|
-
const [map, setMap] = (0,
|
|
923
|
-
const [layers, setLayers] = (0,
|
|
924
|
-
const [effectiveStates, setEffectiveStates] = (0,
|
|
925
|
-
const [loadingMap, setLoadingMap] = (0,
|
|
926
|
-
const [mapError, setMapError] = (0,
|
|
927
|
-
const [mapInstance, setMapInstance] = (0,
|
|
928
|
-
const [panesReady, setPanesReady] = (0,
|
|
929
|
-
const [currentZoom, setCurrentZoom] = (0,
|
|
930
|
-
const [
|
|
1144
|
+
const [map, setMap] = (0, import_react4.useState)(null);
|
|
1145
|
+
const [layers, setLayers] = (0, import_react4.useState)([]);
|
|
1146
|
+
const [effectiveStates, setEffectiveStates] = (0, import_react4.useState)([]);
|
|
1147
|
+
const [loadingMap, setLoadingMap] = (0, import_react4.useState)(false);
|
|
1148
|
+
const [mapError, setMapError] = (0, import_react4.useState)(null);
|
|
1149
|
+
const [mapInstance, setMapInstance] = (0, import_react4.useState)(null);
|
|
1150
|
+
const [panesReady, setPanesReady] = (0, import_react4.useState)(false);
|
|
1151
|
+
const [currentZoom, setCurrentZoom] = (0, import_react4.useState)(initialZoom ?? DEFAULT_ZOOM);
|
|
1152
|
+
const [isPopupOpen, setIsPopupOpen] = (0, import_react4.useState)(false);
|
|
1153
|
+
const [isMobile, setIsMobile] = (0, import_react4.useState)(() => {
|
|
931
1154
|
if (typeof window === "undefined") return false;
|
|
932
1155
|
return window.matchMedia("(max-width: 768px)").matches;
|
|
933
1156
|
});
|
|
934
|
-
const normalizedLayers = (0,
|
|
935
|
-
(0,
|
|
1157
|
+
const normalizedLayers = (0, import_react4.useMemo)(() => normalizeMapLayers(map), [map]);
|
|
1158
|
+
(0, import_react4.useEffect)(() => {
|
|
936
1159
|
if (typeof window === "undefined") return;
|
|
937
1160
|
const mql = window.matchMedia("(max-width: 768px)");
|
|
938
1161
|
const onChange = (e) => {
|
|
@@ -950,12 +1173,37 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
950
1173
|
}
|
|
951
1174
|
return;
|
|
952
1175
|
}, []);
|
|
953
|
-
(0,
|
|
1176
|
+
(0, import_react4.useEffect)(() => {
|
|
954
1177
|
if (featureInfoMode === "popup") {
|
|
955
1178
|
ensurePopupStyles();
|
|
956
1179
|
}
|
|
957
1180
|
}, [featureInfoMode]);
|
|
958
|
-
|
|
1181
|
+
(0, import_react4.useEffect)(() => {
|
|
1182
|
+
if (featureInfoMode !== "popup") {
|
|
1183
|
+
setIsPopupOpen(false);
|
|
1184
|
+
}
|
|
1185
|
+
}, [featureInfoMode]);
|
|
1186
|
+
(0, import_react4.useEffect)(() => {
|
|
1187
|
+
if (!mapInstance) return;
|
|
1188
|
+
const popupPane = mapInstance.getPane("popupPane");
|
|
1189
|
+
if (popupPane) {
|
|
1190
|
+
popupPane.style.zIndex = "800";
|
|
1191
|
+
}
|
|
1192
|
+
const labelsPane = mapInstance.getPane(LABELS_PANE_NAME) ?? mapInstance.createPane(LABELS_PANE_NAME);
|
|
1193
|
+
labelsPane.style.zIndex = "600";
|
|
1194
|
+
}, [mapInstance]);
|
|
1195
|
+
(0, import_react4.useEffect)(() => {
|
|
1196
|
+
if (!mapInstance) return;
|
|
1197
|
+
const handlePopupOpen = () => setIsPopupOpen(true);
|
|
1198
|
+
const handlePopupClose = () => setIsPopupOpen(false);
|
|
1199
|
+
mapInstance.on("popupopen", handlePopupOpen);
|
|
1200
|
+
mapInstance.on("popupclose", handlePopupClose);
|
|
1201
|
+
return () => {
|
|
1202
|
+
mapInstance.off("popupopen", handlePopupOpen);
|
|
1203
|
+
mapInstance.off("popupclose", handlePopupClose);
|
|
1204
|
+
};
|
|
1205
|
+
}, [mapInstance]);
|
|
1206
|
+
const layerStyleIndex = (0, import_react4.useMemo)(() => {
|
|
959
1207
|
const index = /* @__PURE__ */ new Map();
|
|
960
1208
|
(map?.mapLayers ?? []).forEach((entry) => {
|
|
961
1209
|
const layerStyle = entry.layer?.style ?? entry.mapLayer?.layer?.style ?? entry.style ?? null;
|
|
@@ -966,7 +1214,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
966
1214
|
});
|
|
967
1215
|
return index;
|
|
968
1216
|
}, [map]);
|
|
969
|
-
const labelKeyIndex = (0,
|
|
1217
|
+
const labelKeyIndex = (0, import_react4.useMemo)(() => {
|
|
970
1218
|
const index = /* @__PURE__ */ new Map();
|
|
971
1219
|
normalizedLayers.forEach((entry) => {
|
|
972
1220
|
const label = entry.layer?.label ?? entry.mapLayer?.label ?? entry.mapLayer.layerConfig?.label;
|
|
@@ -976,7 +1224,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
976
1224
|
});
|
|
977
1225
|
return index;
|
|
978
1226
|
}, [normalizedLayers]);
|
|
979
|
-
const layerMetaIndex = (0,
|
|
1227
|
+
const layerMetaIndex = (0, import_react4.useMemo)(() => {
|
|
980
1228
|
const index = /* @__PURE__ */ new Map();
|
|
981
1229
|
normalizedLayers.forEach((entry) => {
|
|
982
1230
|
index.set(String(entry.layerId), {
|
|
@@ -986,7 +1234,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
986
1234
|
});
|
|
987
1235
|
return index;
|
|
988
1236
|
}, [normalizedLayers]);
|
|
989
|
-
const overlayStyleFunction = (0,
|
|
1237
|
+
const overlayStyleFunction = (0, import_react4.useMemo)(() => {
|
|
990
1238
|
return (feature) => {
|
|
991
1239
|
const featureLayerId = getFeatureLayerId(feature);
|
|
992
1240
|
const featureStyleOverrides = getFeatureStyleOverrides(feature);
|
|
@@ -1005,11 +1253,15 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1005
1253
|
return defaultOptions;
|
|
1006
1254
|
};
|
|
1007
1255
|
}, [layerStyleIndex, mapLayers, overlayStyle]);
|
|
1008
|
-
const
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
(0,
|
|
1256
|
+
const overlayStyleFn = (0, import_react4.useCallback)(
|
|
1257
|
+
(feature, _layerType, _baseOpacity) => overlayStyleFunction(feature),
|
|
1258
|
+
[overlayStyleFunction]
|
|
1259
|
+
);
|
|
1260
|
+
const [baseStates, setBaseStates] = (0, import_react4.useState)([]);
|
|
1261
|
+
const [mapOverrides, setMapOverrides] = (0, import_react4.useState)([]);
|
|
1262
|
+
const [controlOverrides, setControlOverrides] = (0, import_react4.useState)([]);
|
|
1263
|
+
const [uiOverrides, setUiOverrides] = (0, import_react4.useState)([]);
|
|
1264
|
+
(0, import_react4.useEffect)(() => {
|
|
1013
1265
|
let isMounted = true;
|
|
1014
1266
|
setLoadingMap(true);
|
|
1015
1267
|
setMapError(null);
|
|
@@ -1032,7 +1284,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1032
1284
|
isMounted = false;
|
|
1033
1285
|
};
|
|
1034
1286
|
}, [client.maps, mapId, onError, onLoadingChange]);
|
|
1035
|
-
(0,
|
|
1287
|
+
(0, import_react4.useEffect)(() => {
|
|
1036
1288
|
if (normalizedLayers.length === 0) {
|
|
1037
1289
|
setLayers([]);
|
|
1038
1290
|
setBaseStates([]);
|
|
@@ -1063,7 +1315,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1063
1315
|
setMapOverrides(initialOverrides);
|
|
1064
1316
|
setUiOverrides([]);
|
|
1065
1317
|
}, [normalizedLayers]);
|
|
1066
|
-
(0,
|
|
1318
|
+
(0, import_react4.useEffect)(() => {
|
|
1067
1319
|
if (!layerControls) {
|
|
1068
1320
|
setControlOverrides([]);
|
|
1069
1321
|
return;
|
|
@@ -1075,7 +1327,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1075
1327
|
}));
|
|
1076
1328
|
setControlOverrides(overrides);
|
|
1077
1329
|
}, [layerControls]);
|
|
1078
|
-
(0,
|
|
1330
|
+
(0, import_react4.useEffect)(() => {
|
|
1079
1331
|
if (layerStates) {
|
|
1080
1332
|
return;
|
|
1081
1333
|
}
|
|
@@ -1085,12 +1337,12 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1085
1337
|
onLayerStateChange?.(reset);
|
|
1086
1338
|
}
|
|
1087
1339
|
}, [baseStates, effectiveStates.length, layerControls, layerStates, onLayerStateChange]);
|
|
1088
|
-
(0,
|
|
1340
|
+
(0, import_react4.useEffect)(() => {
|
|
1089
1341
|
if (layerStates) {
|
|
1090
1342
|
setEffectiveStates(layerStates);
|
|
1091
1343
|
}
|
|
1092
1344
|
}, [layerStates]);
|
|
1093
|
-
(0,
|
|
1345
|
+
(0, import_react4.useEffect)(() => {
|
|
1094
1346
|
if (layerStates) {
|
|
1095
1347
|
return;
|
|
1096
1348
|
}
|
|
@@ -1103,11 +1355,11 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1103
1355
|
setEffectiveStates(next);
|
|
1104
1356
|
onLayerStateChange?.(next);
|
|
1105
1357
|
}, [baseStates, controlOverrides, layerStates, mapOverrides, onLayerStateChange, uiOverrides]);
|
|
1106
|
-
(0,
|
|
1358
|
+
(0, import_react4.useEffect)(() => {
|
|
1107
1359
|
if (!Array.isArray(layerControls) || layerControls.length > 0) return;
|
|
1108
1360
|
setUiOverrides([]);
|
|
1109
1361
|
}, [layerControls]);
|
|
1110
|
-
(0,
|
|
1362
|
+
(0, import_react4.useEffect)(() => {
|
|
1111
1363
|
if (layerStates) {
|
|
1112
1364
|
return;
|
|
1113
1365
|
}
|
|
@@ -1127,18 +1379,13 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1127
1379
|
return [...filtered, nextEntry];
|
|
1128
1380
|
});
|
|
1129
1381
|
};
|
|
1130
|
-
const updateOpacityFromUi = (0,
|
|
1382
|
+
const updateOpacityFromUi = (0, import_react4.useCallback)(
|
|
1131
1383
|
(layerId, uiOpacity) => {
|
|
1132
1384
|
const meta = layerMetaIndex.get(String(layerId));
|
|
1133
|
-
const
|
|
1385
|
+
const baseOpacity = clampOpacity3(uiOpacity);
|
|
1386
|
+
const effectiveOpacity = calculateZoomBasedOpacity(
|
|
1134
1387
|
currentZoom,
|
|
1135
|
-
meta?.layerType,
|
|
1136
|
-
meta?.geometryType
|
|
1137
|
-
);
|
|
1138
|
-
const baseOpacity = clampOpacity3(uiOpacity / zoomFactor);
|
|
1139
|
-
const effectiveOpacity = getEffectiveLayerOpacity(
|
|
1140
1388
|
baseOpacity,
|
|
1141
|
-
currentZoom,
|
|
1142
1389
|
meta?.layerType,
|
|
1143
1390
|
meta?.geometryType
|
|
1144
1391
|
);
|
|
@@ -1171,7 +1418,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1171
1418
|
},
|
|
1172
1419
|
[currentZoom, effectiveStates, layerMetaIndex, layerStates, onLayerStateChange]
|
|
1173
1420
|
);
|
|
1174
|
-
const center = (0,
|
|
1421
|
+
const center = (0, import_react4.useMemo)(() => {
|
|
1175
1422
|
if (initialCenter) {
|
|
1176
1423
|
return initialCenter;
|
|
1177
1424
|
}
|
|
@@ -1182,36 +1429,30 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1182
1429
|
return DEFAULT_CENTER;
|
|
1183
1430
|
}, [initialCenter, map?.settings?.center]);
|
|
1184
1431
|
const zoom = initialZoom ?? map?.settings?.zoom ?? DEFAULT_ZOOM;
|
|
1185
|
-
(0,
|
|
1432
|
+
(0, import_react4.useEffect)(() => {
|
|
1186
1433
|
setCurrentZoom(zoom);
|
|
1187
1434
|
}, [zoom]);
|
|
1188
|
-
const decoratedLayers = (0,
|
|
1435
|
+
const decoratedLayers = (0, import_react4.useMemo)(() => {
|
|
1189
1436
|
return layers.map((layer) => ({
|
|
1190
1437
|
...layer,
|
|
1191
1438
|
effective: effectiveStates.find((state) => state.layerId === layer.mapLayer.layerId),
|
|
1192
1439
|
data: layerGeojson?.[layer.mapLayer.layerId] ?? layerGeojson?.[String(layer.mapLayer.layerId)] ?? null
|
|
1193
1440
|
}));
|
|
1194
1441
|
}, [effectiveStates, layerGeojson, layers]);
|
|
1195
|
-
const orderedLayers = (0,
|
|
1442
|
+
const orderedLayers = (0, import_react4.useMemo)(() => {
|
|
1196
1443
|
return [...decoratedLayers].filter((layer) => layer.effective?.visible && layer.data).sort((a, b) => a.displayOrder - b.displayOrder);
|
|
1197
1444
|
}, [decoratedLayers]);
|
|
1198
|
-
const
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
const autoZoomBBox = (0, import_react.useMemo)(() => {
|
|
1204
|
-
if (explicitZoomBBox) return null;
|
|
1205
|
-
const visibleBBoxes = orderedLayers.map((layer) => computeBBoxFromGeojson(layer.data));
|
|
1206
|
-
return mergeBBoxes(visibleBBoxes);
|
|
1207
|
-
}, [explicitZoomBBox, orderedLayers]);
|
|
1208
|
-
const resolveLayerStyle = (0, import_react.useCallback)(
|
|
1445
|
+
const autoZoomGeojson = (0, import_react4.useMemo)(
|
|
1446
|
+
() => orderedLayers.map((layer) => layer.data).filter((collection) => !!collection),
|
|
1447
|
+
[orderedLayers]
|
|
1448
|
+
);
|
|
1449
|
+
const resolveLayerStyle = (0, import_react4.useCallback)(
|
|
1209
1450
|
(layerId) => {
|
|
1210
1451
|
return getStyleByLayerId(layerId, mapLayers) ?? layerStyleIndex.get(String(layerId)) ?? null;
|
|
1211
1452
|
},
|
|
1212
1453
|
[layerStyleIndex, mapLayers]
|
|
1213
1454
|
);
|
|
1214
|
-
const labelMarkers = (0,
|
|
1455
|
+
const labelMarkers = (0, import_react4.useMemo)(() => {
|
|
1215
1456
|
const markers = [];
|
|
1216
1457
|
decoratedLayers.forEach((layerState) => {
|
|
1217
1458
|
if (!layerState.effective?.visible) return;
|
|
@@ -1221,7 +1462,14 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1221
1462
|
if (!data) return;
|
|
1222
1463
|
const resolvedStyle = resolveLayerStyle(layerState.mapLayer.layerId);
|
|
1223
1464
|
const layerColor = resolvedStyle?.fillColor ?? resolvedStyle?.color ?? "rgba(37, 99, 235, 1)";
|
|
1224
|
-
const
|
|
1465
|
+
const meta = layerMetaIndex.get(String(layerState.mapLayer.layerId));
|
|
1466
|
+
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
1467
|
+
const opacity = calculateZoomBasedOpacity(
|
|
1468
|
+
currentZoom,
|
|
1469
|
+
baseOpacity,
|
|
1470
|
+
meta?.layerType,
|
|
1471
|
+
meta?.geometryType
|
|
1472
|
+
);
|
|
1225
1473
|
data.features.forEach((feature, index) => {
|
|
1226
1474
|
const properties = feature.properties;
|
|
1227
1475
|
const value = properties?.[labelKey];
|
|
@@ -1240,26 +1488,24 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1240
1488
|
});
|
|
1241
1489
|
});
|
|
1242
1490
|
return markers;
|
|
1243
|
-
}, [decoratedLayers, labelKeyIndex, resolveLayerStyle]);
|
|
1244
|
-
const ensureLayerPanes = (0,
|
|
1491
|
+
}, [currentZoom, decoratedLayers, labelKeyIndex, layerMetaIndex, resolveLayerStyle]);
|
|
1492
|
+
const ensureLayerPanes = (0, import_react4.useCallback)(
|
|
1245
1493
|
(targetMap, targetLayers) => {
|
|
1246
1494
|
const baseZIndex = 400;
|
|
1247
1495
|
targetLayers.forEach((layer) => {
|
|
1248
1496
|
const order = Number.isFinite(layer.displayOrder) ? layer.displayOrder : 0;
|
|
1497
|
+
const orderOffset = Math.max(0, Math.min(order, 150));
|
|
1249
1498
|
const fillPaneName = `zenit-layer-${layer.layerId}-fill`;
|
|
1250
1499
|
const pointPaneName = `zenit-layer-${layer.layerId}-points`;
|
|
1251
|
-
const labelPaneName = `zenit-layer-${layer.layerId}-labels`;
|
|
1252
1500
|
const fillPane = targetMap.getPane(fillPaneName) ?? targetMap.createPane(fillPaneName);
|
|
1253
1501
|
const pointPane = targetMap.getPane(pointPaneName) ?? targetMap.createPane(pointPaneName);
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
pointPane.style.zIndex = String(baseZIndex + order + 1e3);
|
|
1257
|
-
labelPane.style.zIndex = String(baseZIndex + order + 2e3);
|
|
1502
|
+
fillPane.style.zIndex = String(baseZIndex + orderOffset);
|
|
1503
|
+
pointPane.style.zIndex = String(baseZIndex + orderOffset + 100);
|
|
1258
1504
|
});
|
|
1259
1505
|
},
|
|
1260
1506
|
[]
|
|
1261
1507
|
);
|
|
1262
|
-
const handleMapReady = (0,
|
|
1508
|
+
const handleMapReady = (0, import_react4.useCallback)(
|
|
1263
1509
|
(instance) => {
|
|
1264
1510
|
setPanesReady(false);
|
|
1265
1511
|
setMapInstance(instance);
|
|
@@ -1267,7 +1513,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1267
1513
|
},
|
|
1268
1514
|
[onMapReady]
|
|
1269
1515
|
);
|
|
1270
|
-
(0,
|
|
1516
|
+
(0, import_react4.useEffect)(() => {
|
|
1271
1517
|
if (!mapInstance) {
|
|
1272
1518
|
setPanesReady(false);
|
|
1273
1519
|
return;
|
|
@@ -1281,24 +1527,25 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1281
1527
|
}));
|
|
1282
1528
|
ensureLayerPanes(mapInstance, layerTargets);
|
|
1283
1529
|
const first = layerTargets[0];
|
|
1284
|
-
const testPane = mapInstance.getPane(`zenit-layer-${first.layerId}-
|
|
1285
|
-
|
|
1530
|
+
const testPane = mapInstance.getPane(`zenit-layer-${first.layerId}-fill`);
|
|
1531
|
+
const labelsPane = mapInstance.getPane(LABELS_PANE_NAME);
|
|
1532
|
+
if (testPane && labelsPane) {
|
|
1286
1533
|
setPanesReady(true);
|
|
1287
1534
|
}
|
|
1288
1535
|
}, [mapInstance, orderedLayers, ensureLayerPanes]);
|
|
1289
|
-
const overlayOnEachFeature = (0,
|
|
1536
|
+
const overlayOnEachFeature = (0, import_react4.useMemo)(() => {
|
|
1290
1537
|
return (feature, layer) => {
|
|
1291
1538
|
const layerId = getFeatureLayerId(feature) ?? void 0;
|
|
1292
1539
|
const geometryType = feature?.geometry?.type;
|
|
1293
|
-
const isPointFeature = geometryType === "Point" || geometryType === "MultiPoint" || layer instanceof
|
|
1294
|
-
const originalStyle = layer instanceof
|
|
1540
|
+
const isPointFeature = geometryType === "Point" || geometryType === "MultiPoint" || layer instanceof import_leaflet4.default.CircleMarker;
|
|
1541
|
+
const originalStyle = layer instanceof import_leaflet4.default.Path ? {
|
|
1295
1542
|
color: layer.options.color,
|
|
1296
1543
|
weight: layer.options.weight,
|
|
1297
1544
|
fillColor: layer.options.fillColor,
|
|
1298
1545
|
opacity: layer.options.opacity,
|
|
1299
1546
|
fillOpacity: layer.options.fillOpacity
|
|
1300
1547
|
} : null;
|
|
1301
|
-
const originalRadius = layer instanceof
|
|
1548
|
+
const originalRadius = layer instanceof import_leaflet4.default.CircleMarker ? layer.getRadius() : null;
|
|
1302
1549
|
if (featureInfoMode === "popup") {
|
|
1303
1550
|
const content = buildFeaturePopupHtml(feature);
|
|
1304
1551
|
if (content) {
|
|
@@ -1307,11 +1554,10 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1307
1554
|
maxWidth,
|
|
1308
1555
|
minWidth,
|
|
1309
1556
|
maxHeight,
|
|
1310
|
-
className: "
|
|
1557
|
+
className: "custom-leaflet-popup",
|
|
1311
1558
|
autoPan: true,
|
|
1312
1559
|
closeButton: true,
|
|
1313
|
-
keepInView: true
|
|
1314
|
-
offset: import_leaflet.default.point(0, -24)
|
|
1560
|
+
keepInView: true
|
|
1315
1561
|
});
|
|
1316
1562
|
}
|
|
1317
1563
|
}
|
|
@@ -1332,7 +1578,8 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1332
1578
|
id: layerId,
|
|
1333
1579
|
geometry: feature.geometry
|
|
1334
1580
|
}).then((response) => {
|
|
1335
|
-
const
|
|
1581
|
+
const geo = extractGeoJsonFeatureCollection(response);
|
|
1582
|
+
const candidates = geo?.features ?? [];
|
|
1336
1583
|
const resolved = pickIntersectFeature(feature, candidates);
|
|
1337
1584
|
if (!resolved?.properties) return;
|
|
1338
1585
|
const mergedProperties = {
|
|
@@ -1355,7 +1602,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1355
1602
|
onFeatureClick?.(feature, layerId);
|
|
1356
1603
|
});
|
|
1357
1604
|
layer.on("mouseover", () => {
|
|
1358
|
-
if (layer instanceof
|
|
1605
|
+
if (layer instanceof import_leaflet4.default.Path && originalStyle) {
|
|
1359
1606
|
layer.setStyle({
|
|
1360
1607
|
...originalStyle,
|
|
1361
1608
|
weight: (originalStyle.weight ?? 2) + 1,
|
|
@@ -1363,16 +1610,16 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1363
1610
|
fillOpacity: Math.min(1, (originalStyle.fillOpacity ?? 0.8) + 0.1)
|
|
1364
1611
|
});
|
|
1365
1612
|
}
|
|
1366
|
-
if (layer instanceof
|
|
1613
|
+
if (layer instanceof import_leaflet4.default.CircleMarker && typeof originalRadius === "number") {
|
|
1367
1614
|
layer.setRadius(originalRadius + 1);
|
|
1368
1615
|
}
|
|
1369
1616
|
onFeatureHover?.(feature, layerId);
|
|
1370
1617
|
});
|
|
1371
1618
|
layer.on("mouseout", () => {
|
|
1372
|
-
if (layer instanceof
|
|
1619
|
+
if (layer instanceof import_leaflet4.default.Path && originalStyle) {
|
|
1373
1620
|
layer.setStyle(originalStyle);
|
|
1374
1621
|
}
|
|
1375
|
-
if (layer instanceof
|
|
1622
|
+
if (layer instanceof import_leaflet4.default.CircleMarker && typeof originalRadius === "number") {
|
|
1376
1623
|
layer.setRadius(originalRadius);
|
|
1377
1624
|
}
|
|
1378
1625
|
});
|
|
@@ -1384,80 +1631,20 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1384
1631
|
const resolvedStyle = featureStyleOverrides ? { ...style ?? {}, ...featureStyleOverrides } : style;
|
|
1385
1632
|
const geometryType = feature?.geometry?.type;
|
|
1386
1633
|
const resolvedLayerType = layerType ?? geometryType;
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
resolvedLayerType
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
color: resolvedStyle?.color ?? resolvedStyle?.fillColor ?? "#2563eb",
|
|
1399
|
-
weight: resolvedStyle?.weight ?? 2,
|
|
1400
|
-
fillColor: resolvedStyle?.fillColor ?? resolvedStyle?.color ?? "#2563eb",
|
|
1401
|
-
opacity: strokeOpacity,
|
|
1402
|
-
fillOpacity
|
|
1634
|
+
return layerStyleToLeaflet({
|
|
1635
|
+
baseOpacity,
|
|
1636
|
+
zoom: currentZoom,
|
|
1637
|
+
layerStyle: resolvedStyle,
|
|
1638
|
+
geometryType,
|
|
1639
|
+
layerType: resolvedLayerType
|
|
1640
|
+
});
|
|
1641
|
+
};
|
|
1642
|
+
const makeStyleFnForLayer = (layerId) => {
|
|
1643
|
+
return (feature, layerType, baseOpacity) => {
|
|
1644
|
+
return buildLayerStyle(layerId, baseOpacity ?? 1, feature, layerType);
|
|
1403
1645
|
};
|
|
1404
1646
|
};
|
|
1405
|
-
|
|
1406
|
-
const size = 60;
|
|
1407
|
-
const innerSize = 44;
|
|
1408
|
-
const textStyles = getLabelTextStyles(color);
|
|
1409
|
-
const safeLabel = escapeHtml(label);
|
|
1410
|
-
const clampedOpacity = Math.min(1, Math.max(0.92, opacity));
|
|
1411
|
-
const innerBackground = withAlpha(color, 0.9);
|
|
1412
|
-
return import_leaflet.default.divIcon({
|
|
1413
|
-
className: "zenit-label-marker",
|
|
1414
|
-
iconSize: [size, size],
|
|
1415
|
-
iconAnchor: [size / 2, size / 2],
|
|
1416
|
-
html: `
|
|
1417
|
-
<div
|
|
1418
|
-
title="${safeLabel}"
|
|
1419
|
-
style="
|
|
1420
|
-
width:${size}px;
|
|
1421
|
-
height:${size}px;
|
|
1422
|
-
border-radius:9999px;
|
|
1423
|
-
background:rgba(255, 255, 255, 0.95);
|
|
1424
|
-
border:3px solid rgba(255, 255, 255, 1);
|
|
1425
|
-
display:flex;
|
|
1426
|
-
align-items:center;
|
|
1427
|
-
justify-content:center;
|
|
1428
|
-
opacity:${clampedOpacity};
|
|
1429
|
-
box-shadow:0 2px 6px rgba(0, 0, 0, 0.25);
|
|
1430
|
-
pointer-events:none;
|
|
1431
|
-
"
|
|
1432
|
-
>
|
|
1433
|
-
<div
|
|
1434
|
-
style="
|
|
1435
|
-
width:${innerSize}px;
|
|
1436
|
-
height:${innerSize}px;
|
|
1437
|
-
border-radius:9999px;
|
|
1438
|
-
background:${innerBackground};
|
|
1439
|
-
display:flex;
|
|
1440
|
-
align-items:center;
|
|
1441
|
-
justify-content:center;
|
|
1442
|
-
box-shadow:inset 0 0 0 1px rgba(15, 23, 42, 0.12);
|
|
1443
|
-
"
|
|
1444
|
-
>
|
|
1445
|
-
<span
|
|
1446
|
-
style="
|
|
1447
|
-
color:${textStyles.color};
|
|
1448
|
-
font-size:20px;
|
|
1449
|
-
font-weight:800;
|
|
1450
|
-
text-shadow:${textStyles.shadow};
|
|
1451
|
-
"
|
|
1452
|
-
>
|
|
1453
|
-
${safeLabel}
|
|
1454
|
-
</span>
|
|
1455
|
-
</div>
|
|
1456
|
-
</div>
|
|
1457
|
-
`
|
|
1458
|
-
});
|
|
1459
|
-
}, []);
|
|
1460
|
-
(0, import_react.useImperativeHandle)(ref, () => ({
|
|
1647
|
+
(0, import_react4.useImperativeHandle)(ref, () => ({
|
|
1461
1648
|
setLayerOpacity: (layerId, opacity) => {
|
|
1462
1649
|
upsertUiOverride(layerId, { overrideOpacity: opacity });
|
|
1463
1650
|
},
|
|
@@ -1507,10 +1694,10 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1507
1694
|
getMapInstance: () => mapInstance
|
|
1508
1695
|
}), [effectiveStates, mapInstance]);
|
|
1509
1696
|
if (loadingMap) {
|
|
1510
|
-
return /* @__PURE__ */ (0,
|
|
1697
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { padding: 16, height, width }, children: "Cargando mapa..." });
|
|
1511
1698
|
}
|
|
1512
1699
|
if (mapError) {
|
|
1513
|
-
return /* @__PURE__ */ (0,
|
|
1700
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { padding: 16, height, width, color: "red" }, children: [
|
|
1514
1701
|
"Error al cargar mapa: ",
|
|
1515
1702
|
mapError
|
|
1516
1703
|
] });
|
|
@@ -1522,7 +1709,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1522
1709
|
setCurrentZoom(zoomValue);
|
|
1523
1710
|
onZoomChange?.(zoomValue);
|
|
1524
1711
|
};
|
|
1525
|
-
return /* @__PURE__ */ (0,
|
|
1712
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1526
1713
|
"div",
|
|
1527
1714
|
{
|
|
1528
1715
|
style: {
|
|
@@ -1535,88 +1722,111 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1535
1722
|
boxSizing: "border-box"
|
|
1536
1723
|
},
|
|
1537
1724
|
children: [
|
|
1538
|
-
/* @__PURE__ */ (0,
|
|
1539
|
-
|
|
1725
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1726
|
+
"div",
|
|
1540
1727
|
{
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_leaflet.ZoomControl, { position: "topright" }),
|
|
1555
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MapInstanceBridge, { onReady: handleMapReady }),
|
|
1556
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FitToBounds, { bbox: explicitZoomBBox ?? void 0 }),
|
|
1557
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AutoFitToBounds, { bbox: autoZoomBBox ?? void 0, enabled: !explicitZoomBBox }),
|
|
1558
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ZoomBasedOpacityHandler, { onZoomChange: handleZoomChange }),
|
|
1559
|
-
orderedLayers.map((layerState) => {
|
|
1560
|
-
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
1561
|
-
const fillPaneName = `zenit-layer-${layerState.mapLayer.layerId}-fill`;
|
|
1562
|
-
const pointsPaneName = `zenit-layer-${layerState.mapLayer.layerId}-points`;
|
|
1563
|
-
const labelPaneName = `zenit-layer-${layerState.mapLayer.layerId}-labels`;
|
|
1564
|
-
const layerType = layerState.layer?.layerType ?? layerState.mapLayer.layerType ?? void 0;
|
|
1565
|
-
const data = layerState.data?.features ?? [];
|
|
1566
|
-
const fillFeatures = data.filter(isNonPointGeometry);
|
|
1567
|
-
const pointFeatures = data.filter(isPointGeometry);
|
|
1568
|
-
const fillData = fillFeatures.length > 0 ? buildFeatureCollection(fillFeatures) : null;
|
|
1569
|
-
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
1570
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.default.Fragment, { children: [
|
|
1571
|
-
fillData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1572
|
-
import_react_leaflet.GeoJSON,
|
|
1728
|
+
className: `zenit-map-shell${isPopupOpen ? " popup-open" : ""}`,
|
|
1729
|
+
style: { flex: 1, position: "relative" },
|
|
1730
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1731
|
+
import_react_leaflet4.MapContainer,
|
|
1732
|
+
{
|
|
1733
|
+
center,
|
|
1734
|
+
zoom,
|
|
1735
|
+
style: { height: "100%", width: "100%" },
|
|
1736
|
+
scrollWheelZoom: true,
|
|
1737
|
+
zoomControl: false,
|
|
1738
|
+
children: [
|
|
1739
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1740
|
+
import_react_leaflet4.TileLayer,
|
|
1573
1741
|
{
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
style: (feature) => buildLayerStyle(layerState.mapLayer.layerId, baseOpacity, feature, layerType),
|
|
1577
|
-
onEachFeature: overlayOnEachFeature
|
|
1742
|
+
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
1743
|
+
attribution: "\xA9 OpenStreetMap contributors"
|
|
1578
1744
|
}
|
|
1579
1745
|
),
|
|
1580
|
-
|
|
1581
|
-
|
|
1746
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_leaflet4.ZoomControl, { position: "topright" }),
|
|
1747
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MapInstanceBridge, { onReady: handleMapReady }),
|
|
1748
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1749
|
+
BBoxZoomHandler,
|
|
1582
1750
|
{
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
radius: isMobile ? 8 : 6,
|
|
1587
|
-
...buildLayerStyle(layerState.mapLayer.layerId, baseOpacity, feature, layerType)
|
|
1588
|
-
}),
|
|
1589
|
-
onEachFeature: overlayOnEachFeature
|
|
1751
|
+
bbox: zoomToBbox ?? void 0,
|
|
1752
|
+
geojson: zoomToGeojson ?? void 0,
|
|
1753
|
+
autoGeojson: autoZoomGeojson
|
|
1590
1754
|
}
|
|
1591
1755
|
),
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1756
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ZoomBasedOpacityHandler, { onZoomChange: handleZoomChange }),
|
|
1757
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LocationControl, {}),
|
|
1758
|
+
orderedLayers.map((layerState) => {
|
|
1759
|
+
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
1760
|
+
const fillPaneName = `zenit-layer-${layerState.mapLayer.layerId}-fill`;
|
|
1761
|
+
const pointsPaneName = `zenit-layer-${layerState.mapLayer.layerId}-points`;
|
|
1762
|
+
const layerType = layerState.layer?.layerType ?? layerState.mapLayer.layerType ?? void 0;
|
|
1763
|
+
const labelKey = labelKeyIndex.get(String(layerState.mapLayer.layerId));
|
|
1764
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.default.Fragment, { children: [
|
|
1765
|
+
layerState.data && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1766
|
+
LayerGeoJson,
|
|
1767
|
+
{
|
|
1768
|
+
layerId: layerState.mapLayer.layerId,
|
|
1769
|
+
data: layerState.data,
|
|
1770
|
+
baseOpacity,
|
|
1771
|
+
isMobile,
|
|
1772
|
+
panesReady,
|
|
1773
|
+
mapInstance,
|
|
1774
|
+
fillPaneName,
|
|
1775
|
+
pointsPaneName,
|
|
1776
|
+
layerType,
|
|
1777
|
+
styleFn: makeStyleFnForLayer(layerState.mapLayer.layerId),
|
|
1778
|
+
onEachFeature: overlayOnEachFeature,
|
|
1779
|
+
onPolygonLabel: labelKey ? (feature, layer) => {
|
|
1780
|
+
const geometryType = feature?.geometry?.type;
|
|
1781
|
+
if (geometryType !== "Polygon" && geometryType !== "MultiPolygon") return;
|
|
1782
|
+
const properties = feature?.properties;
|
|
1783
|
+
const value = properties?.[labelKey];
|
|
1784
|
+
if (!value || !layer.bindTooltip) return;
|
|
1785
|
+
layer.bindTooltip(String(value), {
|
|
1786
|
+
sticky: true,
|
|
1787
|
+
direction: "center",
|
|
1788
|
+
opacity: 0.9,
|
|
1789
|
+
className: "polygon-label-tooltip"
|
|
1790
|
+
});
|
|
1791
|
+
} : void 0
|
|
1792
|
+
}
|
|
1793
|
+
),
|
|
1794
|
+
panesReady && mapInstance?.getPane(LABELS_PANE_NAME) ? labelMarkers.filter(
|
|
1795
|
+
(marker) => String(marker.layerId) === String(layerState.mapLayer.layerId)
|
|
1796
|
+
).map((marker) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1797
|
+
import_react_leaflet4.Marker,
|
|
1798
|
+
{
|
|
1799
|
+
position: marker.position,
|
|
1800
|
+
icon: createCustomIcon(marker.label, marker.opacity, marker.color),
|
|
1801
|
+
interactive: false,
|
|
1802
|
+
pane: LABELS_PANE_NAME
|
|
1803
|
+
},
|
|
1804
|
+
marker.key
|
|
1805
|
+
)) : null
|
|
1806
|
+
] }, layerState.mapLayer.layerId.toString());
|
|
1807
|
+
}),
|
|
1808
|
+
overlayGeojson && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1809
|
+
LayerGeoJson,
|
|
1596
1810
|
{
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
},
|
|
1617
|
-
String(mapId)
|
|
1618
|
-
) }),
|
|
1619
|
-
showLayerPanel && decoratedLayers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1811
|
+
layerId: "overlay-geojson",
|
|
1812
|
+
data: overlayGeojson,
|
|
1813
|
+
baseOpacity: 1,
|
|
1814
|
+
isMobile,
|
|
1815
|
+
panesReady,
|
|
1816
|
+
mapInstance,
|
|
1817
|
+
fillPaneName: "zenit-overlay-fill",
|
|
1818
|
+
pointsPaneName: "zenit-overlay-points",
|
|
1819
|
+
styleFn: overlayStyleFn,
|
|
1820
|
+
onEachFeature: overlayOnEachFeature
|
|
1821
|
+
}
|
|
1822
|
+
)
|
|
1823
|
+
]
|
|
1824
|
+
},
|
|
1825
|
+
String(mapId)
|
|
1826
|
+
)
|
|
1827
|
+
}
|
|
1828
|
+
),
|
|
1829
|
+
showLayerPanel && decoratedLayers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1620
1830
|
"div",
|
|
1621
1831
|
{
|
|
1622
1832
|
style: {
|
|
@@ -1629,7 +1839,7 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1629
1839
|
overflowY: "auto"
|
|
1630
1840
|
},
|
|
1631
1841
|
children: [
|
|
1632
|
-
overlayGeojson && /* @__PURE__ */ (0,
|
|
1842
|
+
overlayGeojson && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1633
1843
|
"div",
|
|
1634
1844
|
{
|
|
1635
1845
|
style: {
|
|
@@ -1641,8 +1851,8 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1641
1851
|
marginBottom: 12
|
|
1642
1852
|
},
|
|
1643
1853
|
children: [
|
|
1644
|
-
/* @__PURE__ */ (0,
|
|
1645
|
-
/* @__PURE__ */ (0,
|
|
1854
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontWeight: 600, marginBottom: 4 }, children: "Overlay activo" }),
|
|
1855
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { fontSize: 13 }, children: [
|
|
1646
1856
|
"GeoJSON externo con ",
|
|
1647
1857
|
(overlayGeojson.features?.length ?? 0).toLocaleString(),
|
|
1648
1858
|
" elementos."
|
|
@@ -1650,14 +1860,14 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1650
1860
|
]
|
|
1651
1861
|
}
|
|
1652
1862
|
),
|
|
1653
|
-
/* @__PURE__ */ (0,
|
|
1654
|
-
decoratedLayers.map((layerState) => /* @__PURE__ */ (0,
|
|
1863
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontWeight: 600, marginBottom: 12 }, children: "Capas" }),
|
|
1864
|
+
decoratedLayers.map((layerState) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1655
1865
|
"div",
|
|
1656
1866
|
{
|
|
1657
1867
|
style: { borderBottom: "1px solid #e5e7eb", paddingBottom: 10, marginBottom: 10 },
|
|
1658
1868
|
children: [
|
|
1659
|
-
/* @__PURE__ */ (0,
|
|
1660
|
-
/* @__PURE__ */ (0,
|
|
1869
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
|
1870
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1661
1871
|
"input",
|
|
1662
1872
|
{
|
|
1663
1873
|
type: "checkbox",
|
|
@@ -1668,17 +1878,17 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1668
1878
|
}
|
|
1669
1879
|
}
|
|
1670
1880
|
),
|
|
1671
|
-
/* @__PURE__ */ (0,
|
|
1881
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: layerState.layer?.name ?? `Capa ${layerState.mapLayer.layerId}` })
|
|
1672
1882
|
] }),
|
|
1673
|
-
/* @__PURE__ */ (0,
|
|
1674
|
-
/* @__PURE__ */ (0,
|
|
1675
|
-
/* @__PURE__ */ (0,
|
|
1676
|
-
/* @__PURE__ */ (0,
|
|
1883
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { marginTop: 8 }, children: [
|
|
1884
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 4 }, children: [
|
|
1885
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "#4a5568" }, children: "Opacidad" }),
|
|
1886
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
|
|
1677
1887
|
Math.round((layerState.effective?.opacity ?? 1) * 100),
|
|
1678
1888
|
"%"
|
|
1679
1889
|
] })
|
|
1680
1890
|
] }),
|
|
1681
|
-
/* @__PURE__ */ (0,
|
|
1891
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1682
1892
|
"input",
|
|
1683
1893
|
{
|
|
1684
1894
|
type: "range",
|
|
@@ -1708,13 +1918,13 @@ var ZenitMap = (0, import_react.forwardRef)(({
|
|
|
1708
1918
|
ZenitMap.displayName = "ZenitMap";
|
|
1709
1919
|
|
|
1710
1920
|
// src/react/ZenitLayerManager.tsx
|
|
1711
|
-
var
|
|
1921
|
+
var import_react5 = __toESM(require("react"));
|
|
1712
1922
|
|
|
1713
1923
|
// src/react/icons.tsx
|
|
1714
1924
|
var import_lucide_react = require("lucide-react");
|
|
1715
1925
|
|
|
1716
1926
|
// src/react/ZenitLayerManager.tsx
|
|
1717
|
-
var
|
|
1927
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1718
1928
|
var FLOAT_TOLERANCE = 1e-3;
|
|
1719
1929
|
function areEffectiveStatesEqual(a, b) {
|
|
1720
1930
|
if (a.length !== b.length) return false;
|
|
@@ -1754,15 +1964,15 @@ var ZenitLayerManager = ({
|
|
|
1754
1964
|
layerFeatureCounts,
|
|
1755
1965
|
mapLayers
|
|
1756
1966
|
}) => {
|
|
1757
|
-
const [map, setMap] = (0,
|
|
1758
|
-
const [loadingMap, setLoadingMap] = (0,
|
|
1759
|
-
const [mapError, setMapError] = (0,
|
|
1760
|
-
const [layers, setLayers] = (0,
|
|
1761
|
-
const [activeTab, setActiveTab] = (0,
|
|
1762
|
-
const [panelVisible, setPanelVisible] = (0,
|
|
1763
|
-
const lastEmittedStatesRef = (0,
|
|
1967
|
+
const [map, setMap] = (0, import_react5.useState)(null);
|
|
1968
|
+
const [loadingMap, setLoadingMap] = (0, import_react5.useState)(false);
|
|
1969
|
+
const [mapError, setMapError] = (0, import_react5.useState)(null);
|
|
1970
|
+
const [layers, setLayers] = (0, import_react5.useState)([]);
|
|
1971
|
+
const [activeTab, setActiveTab] = (0, import_react5.useState)("layers");
|
|
1972
|
+
const [panelVisible, setPanelVisible] = (0, import_react5.useState)(true);
|
|
1973
|
+
const lastEmittedStatesRef = (0, import_react5.useRef)(null);
|
|
1764
1974
|
const isControlled = Array.isArray(layerStates) && typeof onLayerStatesChange === "function";
|
|
1765
|
-
const baseStates = (0,
|
|
1975
|
+
const baseStates = (0, import_react5.useMemo)(
|
|
1766
1976
|
() => initLayerStates(
|
|
1767
1977
|
layers.map((entry) => ({
|
|
1768
1978
|
...entry.mapLayer,
|
|
@@ -1773,7 +1983,7 @@ var ZenitLayerManager = ({
|
|
|
1773
1983
|
),
|
|
1774
1984
|
[layers]
|
|
1775
1985
|
);
|
|
1776
|
-
const overrideStates = (0,
|
|
1986
|
+
const overrideStates = (0, import_react5.useMemo)(
|
|
1777
1987
|
() => layers.map(
|
|
1778
1988
|
(entry) => ({
|
|
1779
1989
|
layerId: entry.mapLayer.layerId,
|
|
@@ -1783,11 +1993,11 @@ var ZenitLayerManager = ({
|
|
|
1783
1993
|
),
|
|
1784
1994
|
[layers]
|
|
1785
1995
|
);
|
|
1786
|
-
const effectiveStates = (0,
|
|
1996
|
+
const effectiveStates = (0, import_react5.useMemo)(
|
|
1787
1997
|
() => layerStates ?? applyLayerOverrides(baseStates, overrideStates),
|
|
1788
1998
|
[baseStates, layerStates, overrideStates]
|
|
1789
1999
|
);
|
|
1790
|
-
const layerMetaIndex = (0,
|
|
2000
|
+
const layerMetaIndex = (0, import_react5.useMemo)(() => {
|
|
1791
2001
|
const index = /* @__PURE__ */ new Map();
|
|
1792
2002
|
mapLayers?.forEach((entry) => {
|
|
1793
2003
|
const key = String(entry.layerId);
|
|
@@ -1801,7 +2011,7 @@ var ZenitLayerManager = ({
|
|
|
1801
2011
|
});
|
|
1802
2012
|
return index;
|
|
1803
2013
|
}, [map, mapLayers]);
|
|
1804
|
-
const resolveUserOpacity =
|
|
2014
|
+
const resolveUserOpacity = import_react5.default.useCallback((state) => {
|
|
1805
2015
|
if (typeof state.overrideOpacity === "number") return state.overrideOpacity;
|
|
1806
2016
|
if (typeof state.overrideOpacity === "string") {
|
|
1807
2017
|
const parsed = Number.parseFloat(state.overrideOpacity);
|
|
@@ -1809,7 +2019,7 @@ var ZenitLayerManager = ({
|
|
|
1809
2019
|
}
|
|
1810
2020
|
return state.opacity ?? 1;
|
|
1811
2021
|
}, []);
|
|
1812
|
-
const resolveEffectiveOpacity =
|
|
2022
|
+
const resolveEffectiveOpacity = import_react5.default.useCallback(
|
|
1813
2023
|
(layerId, userOpacity) => {
|
|
1814
2024
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
1815
2025
|
return userOpacity;
|
|
@@ -1825,7 +2035,7 @@ var ZenitLayerManager = ({
|
|
|
1825
2035
|
},
|
|
1826
2036
|
[autoOpacityConfig, autoOpacityOnZoom, layerMetaIndex, mapZoom]
|
|
1827
2037
|
);
|
|
1828
|
-
const effectiveStatesWithZoom = (0,
|
|
2038
|
+
const effectiveStatesWithZoom = (0, import_react5.useMemo)(() => {
|
|
1829
2039
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
1830
2040
|
return effectiveStates;
|
|
1831
2041
|
}
|
|
@@ -1839,7 +2049,7 @@ var ZenitLayerManager = ({
|
|
|
1839
2049
|
};
|
|
1840
2050
|
});
|
|
1841
2051
|
}, [autoOpacityOnZoom, effectiveStates, mapZoom, resolveEffectiveOpacity, resolveUserOpacity]);
|
|
1842
|
-
(0,
|
|
2052
|
+
(0, import_react5.useEffect)(() => {
|
|
1843
2053
|
let cancelled = false;
|
|
1844
2054
|
setLoadingMap(true);
|
|
1845
2055
|
setMapError(null);
|
|
@@ -1871,12 +2081,12 @@ var ZenitLayerManager = ({
|
|
|
1871
2081
|
cancelled = true;
|
|
1872
2082
|
};
|
|
1873
2083
|
}, [client.maps, mapId]);
|
|
1874
|
-
(0,
|
|
2084
|
+
(0, import_react5.useEffect)(() => {
|
|
1875
2085
|
if (!showUploadTab && activeTab === "upload") {
|
|
1876
2086
|
setActiveTab("layers");
|
|
1877
2087
|
}
|
|
1878
2088
|
}, [activeTab, showUploadTab]);
|
|
1879
|
-
(0,
|
|
2089
|
+
(0, import_react5.useEffect)(() => {
|
|
1880
2090
|
if (isControlled) return;
|
|
1881
2091
|
if (!onLayerStatesChange) return;
|
|
1882
2092
|
const emitStates = autoOpacityOnZoom && typeof mapZoom === "number" ? effectiveStatesWithZoom : effectiveStates;
|
|
@@ -1894,7 +2104,7 @@ var ZenitLayerManager = ({
|
|
|
1894
2104
|
mapZoom,
|
|
1895
2105
|
onLayerStatesChange
|
|
1896
2106
|
]);
|
|
1897
|
-
const updateLayerVisible =
|
|
2107
|
+
const updateLayerVisible = import_react5.default.useCallback(
|
|
1898
2108
|
(layerId, visible) => {
|
|
1899
2109
|
if (!onLayerStatesChange) return;
|
|
1900
2110
|
const next = effectiveStates.map(
|
|
@@ -1904,7 +2114,7 @@ var ZenitLayerManager = ({
|
|
|
1904
2114
|
},
|
|
1905
2115
|
[effectiveStates, onLayerStatesChange]
|
|
1906
2116
|
);
|
|
1907
|
-
const updateLayerOpacity =
|
|
2117
|
+
const updateLayerOpacity = import_react5.default.useCallback(
|
|
1908
2118
|
(layerId, opacity) => {
|
|
1909
2119
|
if (!onLayerStatesChange) return;
|
|
1910
2120
|
const adjustedOpacity = resolveEffectiveOpacity(layerId, opacity);
|
|
@@ -1915,7 +2125,7 @@ var ZenitLayerManager = ({
|
|
|
1915
2125
|
},
|
|
1916
2126
|
[effectiveStates, onLayerStatesChange, resolveEffectiveOpacity]
|
|
1917
2127
|
);
|
|
1918
|
-
const resolveFeatureCount =
|
|
2128
|
+
const resolveFeatureCount = import_react5.default.useCallback(
|
|
1919
2129
|
(layerId, layer) => {
|
|
1920
2130
|
const resolvedFeatureCount = layerFeatureCounts?.[layerId] ?? layerFeatureCounts?.[String(layerId)];
|
|
1921
2131
|
if (typeof resolvedFeatureCount === "number") return resolvedFeatureCount;
|
|
@@ -1924,7 +2134,7 @@ var ZenitLayerManager = ({
|
|
|
1924
2134
|
},
|
|
1925
2135
|
[layerFeatureCounts]
|
|
1926
2136
|
);
|
|
1927
|
-
const decoratedLayers = (0,
|
|
2137
|
+
const decoratedLayers = (0, import_react5.useMemo)(() => {
|
|
1928
2138
|
return layers.map((entry) => ({
|
|
1929
2139
|
...entry,
|
|
1930
2140
|
effective: effectiveStates.find((state) => state.layerId === entry.mapLayer.layerId),
|
|
@@ -1953,7 +2163,7 @@ var ZenitLayerManager = ({
|
|
|
1953
2163
|
return String(a.mapLayer.layerId).localeCompare(String(b.mapLayer.layerId));
|
|
1954
2164
|
});
|
|
1955
2165
|
}, [effectiveStates, layers, resolveFeatureCount]);
|
|
1956
|
-
const resolveLayerStyle =
|
|
2166
|
+
const resolveLayerStyle = import_react5.default.useCallback(
|
|
1957
2167
|
(layerId) => {
|
|
1958
2168
|
const layerKey = String(layerId);
|
|
1959
2169
|
const fromProp = mapLayers?.find((entry) => String(entry.layerId) === layerKey)?.style;
|
|
@@ -1983,10 +2193,10 @@ var ZenitLayerManager = ({
|
|
|
1983
2193
|
...height ? { height } : {}
|
|
1984
2194
|
};
|
|
1985
2195
|
if (loadingMap) {
|
|
1986
|
-
return /* @__PURE__ */ (0,
|
|
2196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: panelStyle, children: "Cargando capas\u2026" });
|
|
1987
2197
|
}
|
|
1988
2198
|
if (mapError) {
|
|
1989
|
-
return /* @__PURE__ */ (0,
|
|
2199
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className, style: { ...panelStyle, color: "#c53030" }, children: [
|
|
1990
2200
|
"Error al cargar mapa: ",
|
|
1991
2201
|
mapError
|
|
1992
2202
|
] });
|
|
@@ -2004,7 +2214,7 @@ var ZenitLayerManager = ({
|
|
|
2004
2214
|
boxShadow: "0 1px 0 rgba(148, 163, 184, 0.25)"
|
|
2005
2215
|
};
|
|
2006
2216
|
const renderLayerCards = () => {
|
|
2007
|
-
return /* @__PURE__ */ (0,
|
|
2217
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: decoratedLayers.map((layerState) => {
|
|
2008
2218
|
const layerId = layerState.mapLayer.layerId;
|
|
2009
2219
|
const layerName = layerState.layerName ?? `Capa ${layerId}`;
|
|
2010
2220
|
const visible = layerState.effective?.visible ?? false;
|
|
@@ -2014,7 +2224,7 @@ var ZenitLayerManager = ({
|
|
|
2014
2224
|
const muted = !visible;
|
|
2015
2225
|
const opacityPercent = Math.round(userOpacity * 100);
|
|
2016
2226
|
const sliderBackground = `linear-gradient(to right, ${layerColor} 0%, ${layerColor} ${opacityPercent}%, #e5e7eb ${opacityPercent}%, #e5e7eb 100%)`;
|
|
2017
|
-
return /* @__PURE__ */ (0,
|
|
2227
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2018
2228
|
"div",
|
|
2019
2229
|
{
|
|
2020
2230
|
className: `zlm-card${muted ? " is-muted" : ""}`,
|
|
@@ -2029,9 +2239,9 @@ var ZenitLayerManager = ({
|
|
|
2029
2239
|
width: "100%"
|
|
2030
2240
|
},
|
|
2031
2241
|
children: [
|
|
2032
|
-
/* @__PURE__ */ (0,
|
|
2033
|
-
/* @__PURE__ */ (0,
|
|
2034
|
-
/* @__PURE__ */ (0,
|
|
2242
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
|
|
2243
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: 10, alignItems: "flex-start", minWidth: 0, flex: 1 }, children: [
|
|
2244
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2035
2245
|
"div",
|
|
2036
2246
|
{
|
|
2037
2247
|
style: {
|
|
@@ -2046,7 +2256,7 @@ var ZenitLayerManager = ({
|
|
|
2046
2256
|
title: "Color de la capa"
|
|
2047
2257
|
}
|
|
2048
2258
|
),
|
|
2049
|
-
showLayerVisibilityIcon && /* @__PURE__ */ (0,
|
|
2259
|
+
showLayerVisibilityIcon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2050
2260
|
"button",
|
|
2051
2261
|
{
|
|
2052
2262
|
type: "button",
|
|
@@ -2057,11 +2267,11 @@ var ZenitLayerManager = ({
|
|
|
2057
2267
|
)
|
|
2058
2268
|
),
|
|
2059
2269
|
"aria-label": visible ? "Ocultar capa" : "Mostrar capa",
|
|
2060
|
-
children: visible ? /* @__PURE__ */ (0,
|
|
2270
|
+
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 })
|
|
2061
2271
|
}
|
|
2062
2272
|
),
|
|
2063
|
-
/* @__PURE__ */ (0,
|
|
2064
|
-
/* @__PURE__ */ (0,
|
|
2273
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { minWidth: 0, flex: 1 }, children: [
|
|
2274
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2065
2275
|
"div",
|
|
2066
2276
|
{
|
|
2067
2277
|
className: "zlm-layer-name",
|
|
@@ -2079,26 +2289,26 @@ var ZenitLayerManager = ({
|
|
|
2079
2289
|
children: layerName
|
|
2080
2290
|
}
|
|
2081
2291
|
),
|
|
2082
|
-
/* @__PURE__ */ (0,
|
|
2292
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: muted ? "#94a3b8" : "#64748b", fontSize: 12 }, children: [
|
|
2083
2293
|
"ID ",
|
|
2084
2294
|
layerId
|
|
2085
2295
|
] })
|
|
2086
2296
|
] })
|
|
2087
2297
|
] }),
|
|
2088
|
-
/* @__PURE__ */ (0,
|
|
2298
|
+
/* @__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: [
|
|
2089
2299
|
featureCount.toLocaleString(),
|
|
2090
2300
|
" features"
|
|
2091
2301
|
] }) })
|
|
2092
2302
|
] }),
|
|
2093
|
-
/* @__PURE__ */ (0,
|
|
2094
|
-
/* @__PURE__ */ (0,
|
|
2095
|
-
/* @__PURE__ */ (0,
|
|
2096
|
-
/* @__PURE__ */ (0,
|
|
2303
|
+
/* @__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: [
|
|
2304
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 6, color: "#64748b", fontSize: 12 }, children: [
|
|
2305
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Opacidad" }),
|
|
2306
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
|
|
2097
2307
|
opacityPercent,
|
|
2098
2308
|
"%"
|
|
2099
2309
|
] })
|
|
2100
2310
|
] }),
|
|
2101
|
-
/* @__PURE__ */ (0,
|
|
2311
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2102
2312
|
"input",
|
|
2103
2313
|
{
|
|
2104
2314
|
className: "zlm-range",
|
|
@@ -2136,8 +2346,8 @@ var ZenitLayerManager = ({
|
|
|
2136
2346
|
);
|
|
2137
2347
|
}) });
|
|
2138
2348
|
};
|
|
2139
|
-
return /* @__PURE__ */ (0,
|
|
2140
|
-
/* @__PURE__ */ (0,
|
|
2349
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: ["zenit-layer-manager", className].filter(Boolean).join(" "), style: panelStyle, children: [
|
|
2350
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
|
|
2141
2351
|
.zenit-layer-manager .zlm-card {
|
|
2142
2352
|
transition: box-shadow 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
|
|
2143
2353
|
box-shadow: 0 6px 16px rgba(15, 23, 42, 0.08);
|
|
@@ -2232,16 +2442,16 @@ var ZenitLayerManager = ({
|
|
|
2232
2442
|
outline-offset: 2px;
|
|
2233
2443
|
}
|
|
2234
2444
|
` }),
|
|
2235
|
-
/* @__PURE__ */ (0,
|
|
2236
|
-
/* @__PURE__ */ (0,
|
|
2237
|
-
/* @__PURE__ */ (0,
|
|
2238
|
-
/* @__PURE__ */ (0,
|
|
2239
|
-
/* @__PURE__ */ (0,
|
|
2445
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: headerStyle, children: [
|
|
2446
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
|
|
2447
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
2448
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontWeight: 800, fontSize: 16, color: "#0f172a" }, children: "Gesti\xF3n de Capas" }),
|
|
2449
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: "#64748b", fontSize: 12 }, children: [
|
|
2240
2450
|
"Mapa #",
|
|
2241
2451
|
map.id
|
|
2242
2452
|
] })
|
|
2243
2453
|
] }),
|
|
2244
|
-
/* @__PURE__ */ (0,
|
|
2454
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2245
2455
|
"button",
|
|
2246
2456
|
{
|
|
2247
2457
|
type: "button",
|
|
@@ -2249,13 +2459,13 @@ var ZenitLayerManager = ({
|
|
|
2249
2459
|
className: "zlm-panel-toggle",
|
|
2250
2460
|
"aria-label": panelVisible ? "Ocultar panel de capas" : "Mostrar panel de capas",
|
|
2251
2461
|
children: [
|
|
2252
|
-
panelVisible ? /* @__PURE__ */ (0,
|
|
2462
|
+
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 }),
|
|
2253
2463
|
panelVisible ? "Ocultar" : "Mostrar"
|
|
2254
2464
|
]
|
|
2255
2465
|
}
|
|
2256
2466
|
)
|
|
2257
2467
|
] }),
|
|
2258
|
-
/* @__PURE__ */ (0,
|
|
2468
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2259
2469
|
"div",
|
|
2260
2470
|
{
|
|
2261
2471
|
style: {
|
|
@@ -2268,26 +2478,26 @@ var ZenitLayerManager = ({
|
|
|
2268
2478
|
background: "#f1f5f9"
|
|
2269
2479
|
},
|
|
2270
2480
|
children: [
|
|
2271
|
-
/* @__PURE__ */ (0,
|
|
2481
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2272
2482
|
"button",
|
|
2273
2483
|
{
|
|
2274
2484
|
type: "button",
|
|
2275
2485
|
className: `zlm-tab${activeTab === "layers" ? " is-active" : ""}`,
|
|
2276
2486
|
onClick: () => setActiveTab("layers"),
|
|
2277
2487
|
children: [
|
|
2278
|
-
/* @__PURE__ */ (0,
|
|
2488
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Layers, { size: 16 }),
|
|
2279
2489
|
"Capas"
|
|
2280
2490
|
]
|
|
2281
2491
|
}
|
|
2282
2492
|
),
|
|
2283
|
-
showUploadTab && /* @__PURE__ */ (0,
|
|
2493
|
+
showUploadTab && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2284
2494
|
"button",
|
|
2285
2495
|
{
|
|
2286
2496
|
type: "button",
|
|
2287
2497
|
className: `zlm-tab${activeTab === "upload" ? " is-active" : ""}`,
|
|
2288
2498
|
onClick: () => setActiveTab("upload"),
|
|
2289
2499
|
children: [
|
|
2290
|
-
/* @__PURE__ */ (0,
|
|
2500
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Upload, { size: 16 }),
|
|
2291
2501
|
"Subir"
|
|
2292
2502
|
]
|
|
2293
2503
|
}
|
|
@@ -2296,15 +2506,15 @@ var ZenitLayerManager = ({
|
|
|
2296
2506
|
}
|
|
2297
2507
|
)
|
|
2298
2508
|
] }),
|
|
2299
|
-
panelVisible && /* @__PURE__ */ (0,
|
|
2509
|
+
panelVisible && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
|
|
2300
2510
|
activeTab === "layers" && renderLayerCards(),
|
|
2301
|
-
showUploadTab && activeTab === "upload" && /* @__PURE__ */ (0,
|
|
2511
|
+
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." })
|
|
2302
2512
|
] })
|
|
2303
2513
|
] });
|
|
2304
2514
|
};
|
|
2305
2515
|
|
|
2306
2516
|
// src/react/ZenitFeatureFilterPanel.tsx
|
|
2307
|
-
var
|
|
2517
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2308
2518
|
var ZenitFeatureFilterPanel = ({
|
|
2309
2519
|
title = "Filtros",
|
|
2310
2520
|
description,
|
|
@@ -2312,7 +2522,7 @@ var ZenitFeatureFilterPanel = ({
|
|
|
2312
2522
|
style,
|
|
2313
2523
|
children
|
|
2314
2524
|
}) => {
|
|
2315
|
-
return /* @__PURE__ */ (0,
|
|
2525
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2316
2526
|
"section",
|
|
2317
2527
|
{
|
|
2318
2528
|
className,
|
|
@@ -2325,22 +2535,22 @@ var ZenitFeatureFilterPanel = ({
|
|
|
2325
2535
|
...style
|
|
2326
2536
|
},
|
|
2327
2537
|
children: [
|
|
2328
|
-
/* @__PURE__ */ (0,
|
|
2329
|
-
/* @__PURE__ */ (0,
|
|
2330
|
-
description && /* @__PURE__ */ (0,
|
|
2538
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("header", { style: { marginBottom: 12 }, children: [
|
|
2539
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { style: { margin: 0, fontSize: 16 }, children: title }),
|
|
2540
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { style: { margin: "6px 0 0", color: "#475569", fontSize: 13 }, children: description })
|
|
2331
2541
|
] }),
|
|
2332
|
-
/* @__PURE__ */ (0,
|
|
2542
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children })
|
|
2333
2543
|
]
|
|
2334
2544
|
}
|
|
2335
2545
|
);
|
|
2336
2546
|
};
|
|
2337
2547
|
|
|
2338
2548
|
// src/react/ai/FloatingChatBox.tsx
|
|
2339
|
-
var
|
|
2340
|
-
var
|
|
2549
|
+
var import_react7 = require("react");
|
|
2550
|
+
var import_react_dom2 = require("react-dom");
|
|
2341
2551
|
|
|
2342
2552
|
// src/react/hooks/use-chat.ts
|
|
2343
|
-
var
|
|
2553
|
+
var import_react6 = require("react");
|
|
2344
2554
|
|
|
2345
2555
|
// src/ai/chat.service.ts
|
|
2346
2556
|
var DEFAULT_ERROR_MESSAGE = "No fue posible completar la solicitud al asistente.";
|
|
@@ -2472,9 +2682,9 @@ var sendMessageStream = async (mapId, request, callbacks = {}, options, config)
|
|
|
2472
2682
|
|
|
2473
2683
|
// src/react/hooks/use-chat.ts
|
|
2474
2684
|
var useSendMessage = (config) => {
|
|
2475
|
-
const [isLoading, setIsLoading] = (0,
|
|
2476
|
-
const [error, setError] = (0,
|
|
2477
|
-
const send = (0,
|
|
2685
|
+
const [isLoading, setIsLoading] = (0, import_react6.useState)(false);
|
|
2686
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
2687
|
+
const send = (0, import_react6.useCallback)(
|
|
2478
2688
|
async (mapId, request, options) => {
|
|
2479
2689
|
setIsLoading(true);
|
|
2480
2690
|
setError(null);
|
|
@@ -2492,18 +2702,18 @@ var useSendMessage = (config) => {
|
|
|
2492
2702
|
return { sendMessage: send, isLoading, error };
|
|
2493
2703
|
};
|
|
2494
2704
|
var useSendMessageStream = (config) => {
|
|
2495
|
-
const [isStreaming, setIsStreaming] = (0,
|
|
2496
|
-
const [streamingText, setStreamingText] = (0,
|
|
2497
|
-
const [completeResponse, setCompleteResponse] = (0,
|
|
2498
|
-
const [error, setError] = (0,
|
|
2499
|
-
const requestIdRef = (0,
|
|
2500
|
-
const reset = (0,
|
|
2705
|
+
const [isStreaming, setIsStreaming] = (0, import_react6.useState)(false);
|
|
2706
|
+
const [streamingText, setStreamingText] = (0, import_react6.useState)("");
|
|
2707
|
+
const [completeResponse, setCompleteResponse] = (0, import_react6.useState)(null);
|
|
2708
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
2709
|
+
const requestIdRef = (0, import_react6.useRef)(0);
|
|
2710
|
+
const reset = (0, import_react6.useCallback)(() => {
|
|
2501
2711
|
setIsStreaming(false);
|
|
2502
2712
|
setStreamingText("");
|
|
2503
2713
|
setCompleteResponse(null);
|
|
2504
2714
|
setError(null);
|
|
2505
2715
|
}, []);
|
|
2506
|
-
const send = (0,
|
|
2716
|
+
const send = (0, import_react6.useCallback)(
|
|
2507
2717
|
async (mapId, request, options) => {
|
|
2508
2718
|
const requestId = requestIdRef.current + 1;
|
|
2509
2719
|
requestIdRef.current = requestId;
|
|
@@ -2557,7 +2767,7 @@ var useSendMessageStream = (config) => {
|
|
|
2557
2767
|
// src/react/components/MarkdownRenderer.tsx
|
|
2558
2768
|
var import_react_markdown = __toESM(require("react-markdown"));
|
|
2559
2769
|
var import_remark_gfm = __toESM(require("remark-gfm"));
|
|
2560
|
-
var
|
|
2770
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2561
2771
|
function normalizeAssistantMarkdown(text) {
|
|
2562
2772
|
if (!text || typeof text !== "string") return "";
|
|
2563
2773
|
let normalized = text;
|
|
@@ -2573,28 +2783,28 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2573
2783
|
if (!normalizedContent) {
|
|
2574
2784
|
return null;
|
|
2575
2785
|
}
|
|
2576
|
-
return /* @__PURE__ */ (0,
|
|
2786
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className, style: { wordBreak: "break-word" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2577
2787
|
import_react_markdown.default,
|
|
2578
2788
|
{
|
|
2579
2789
|
remarkPlugins: [import_remark_gfm.default],
|
|
2580
2790
|
components: {
|
|
2581
2791
|
// Headings with proper spacing
|
|
2582
|
-
h1: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2583
|
-
h2: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2584
|
-
h3: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2585
|
-
h4: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2586
|
-
h5: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2587
|
-
h6: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2792
|
+
h1: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { style: { fontSize: "1.5em", fontWeight: 700, marginTop: "1em", marginBottom: "0.5em" }, ...props, children }),
|
|
2793
|
+
h2: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { style: { fontSize: "1.3em", fontWeight: 700, marginTop: "0.9em", marginBottom: "0.45em" }, ...props, children }),
|
|
2794
|
+
h3: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { style: { fontSize: "1.15em", fontWeight: 600, marginTop: "0.75em", marginBottom: "0.4em" }, ...props, children }),
|
|
2795
|
+
h4: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h4", { style: { fontSize: "1.05em", fontWeight: 600, marginTop: "0.6em", marginBottom: "0.35em" }, ...props, children }),
|
|
2796
|
+
h5: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h5", { style: { fontSize: "1em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
|
|
2797
|
+
h6: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h6", { style: { fontSize: "0.95em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
|
|
2588
2798
|
// Paragraphs with comfortable line height
|
|
2589
|
-
p: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2799
|
+
p: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: { marginTop: "0.5em", marginBottom: "0.5em", lineHeight: 1.6 }, ...props, children }),
|
|
2590
2800
|
// Lists with proper indentation
|
|
2591
|
-
ul: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2592
|
-
ol: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2593
|
-
li: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2801
|
+
ul: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
|
|
2802
|
+
ol: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ol", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
|
|
2803
|
+
li: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { style: { marginTop: "0.25em", marginBottom: "0.25em" }, ...props, children }),
|
|
2594
2804
|
// Code blocks
|
|
2595
2805
|
code: ({ inline, children, ...props }) => {
|
|
2596
2806
|
if (inline) {
|
|
2597
|
-
return /* @__PURE__ */ (0,
|
|
2807
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2598
2808
|
"code",
|
|
2599
2809
|
{
|
|
2600
2810
|
style: {
|
|
@@ -2609,7 +2819,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2609
2819
|
}
|
|
2610
2820
|
);
|
|
2611
2821
|
}
|
|
2612
|
-
return /* @__PURE__ */ (0,
|
|
2822
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2613
2823
|
"code",
|
|
2614
2824
|
{
|
|
2615
2825
|
style: {
|
|
@@ -2629,9 +2839,9 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2629
2839
|
);
|
|
2630
2840
|
},
|
|
2631
2841
|
// Pre (code block wrapper)
|
|
2632
|
-
pre: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2842
|
+
pre: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { style: { margin: 0 }, ...props, children }),
|
|
2633
2843
|
// Blockquotes
|
|
2634
|
-
blockquote: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2844
|
+
blockquote: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2635
2845
|
"blockquote",
|
|
2636
2846
|
{
|
|
2637
2847
|
style: {
|
|
@@ -2647,11 +2857,11 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2647
2857
|
}
|
|
2648
2858
|
),
|
|
2649
2859
|
// Strong/bold
|
|
2650
|
-
strong: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2860
|
+
strong: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { style: { fontWeight: 600 }, ...props, children }),
|
|
2651
2861
|
// Emphasis/italic
|
|
2652
|
-
em: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2862
|
+
em: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("em", { style: { fontStyle: "italic" }, ...props, children }),
|
|
2653
2863
|
// Horizontal rule
|
|
2654
|
-
hr: (props) => /* @__PURE__ */ (0,
|
|
2864
|
+
hr: (props) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2655
2865
|
"hr",
|
|
2656
2866
|
{
|
|
2657
2867
|
style: {
|
|
@@ -2664,7 +2874,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2664
2874
|
}
|
|
2665
2875
|
),
|
|
2666
2876
|
// Tables (GFM)
|
|
2667
|
-
table: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2877
|
+
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)(
|
|
2668
2878
|
"table",
|
|
2669
2879
|
{
|
|
2670
2880
|
style: {
|
|
@@ -2676,7 +2886,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2676
2886
|
children
|
|
2677
2887
|
}
|
|
2678
2888
|
) }),
|
|
2679
|
-
th: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2889
|
+
th: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2680
2890
|
"th",
|
|
2681
2891
|
{
|
|
2682
2892
|
style: {
|
|
@@ -2690,7 +2900,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2690
2900
|
children
|
|
2691
2901
|
}
|
|
2692
2902
|
),
|
|
2693
|
-
td: ({ children, ...props }) => /* @__PURE__ */ (0,
|
|
2903
|
+
td: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2694
2904
|
"td",
|
|
2695
2905
|
{
|
|
2696
2906
|
style: {
|
|
@@ -2708,32 +2918,32 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2708
2918
|
};
|
|
2709
2919
|
|
|
2710
2920
|
// src/react/ai/FloatingChatBox.tsx
|
|
2711
|
-
var
|
|
2712
|
-
var ChatIcon = () => /* @__PURE__ */ (0,
|
|
2713
|
-
var CloseIcon = () => /* @__PURE__ */ (0,
|
|
2714
|
-
/* @__PURE__ */ (0,
|
|
2715
|
-
/* @__PURE__ */ (0,
|
|
2921
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2922
|
+
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" }) });
|
|
2923
|
+
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: [
|
|
2924
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
2925
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
2716
2926
|
] });
|
|
2717
|
-
var ExpandIcon = () => /* @__PURE__ */ (0,
|
|
2718
|
-
/* @__PURE__ */ (0,
|
|
2719
|
-
/* @__PURE__ */ (0,
|
|
2720
|
-
/* @__PURE__ */ (0,
|
|
2721
|
-
/* @__PURE__ */ (0,
|
|
2927
|
+
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: [
|
|
2928
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "15 3 21 3 21 9" }),
|
|
2929
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "9 21 3 21 3 15" }),
|
|
2930
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
|
|
2931
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
|
|
2722
2932
|
] });
|
|
2723
|
-
var CollapseIcon = () => /* @__PURE__ */ (0,
|
|
2724
|
-
/* @__PURE__ */ (0,
|
|
2725
|
-
/* @__PURE__ */ (0,
|
|
2726
|
-
/* @__PURE__ */ (0,
|
|
2727
|
-
/* @__PURE__ */ (0,
|
|
2933
|
+
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: [
|
|
2934
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "4 14 10 14 10 20" }),
|
|
2935
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "20 10 14 10 14 4" }),
|
|
2936
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
|
|
2937
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
|
|
2728
2938
|
] });
|
|
2729
|
-
var SendIcon = () => /* @__PURE__ */ (0,
|
|
2730
|
-
/* @__PURE__ */ (0,
|
|
2731
|
-
/* @__PURE__ */ (0,
|
|
2939
|
+
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: [
|
|
2940
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
|
|
2941
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
2732
2942
|
] });
|
|
2733
|
-
var LayersIcon = () => /* @__PURE__ */ (0,
|
|
2734
|
-
/* @__PURE__ */ (0,
|
|
2735
|
-
/* @__PURE__ */ (0,
|
|
2736
|
-
/* @__PURE__ */ (0,
|
|
2943
|
+
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: [
|
|
2944
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
|
|
2945
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "2 17 12 22 22 17" }),
|
|
2946
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "2 12 12 17 22 12" })
|
|
2737
2947
|
] });
|
|
2738
2948
|
var styles = {
|
|
2739
2949
|
root: {
|
|
@@ -2742,8 +2952,8 @@ var styles = {
|
|
|
2742
2952
|
// Floating button (closed state - wide with text, open state - circular with X)
|
|
2743
2953
|
floatingButton: {
|
|
2744
2954
|
position: "fixed",
|
|
2745
|
-
bottom:
|
|
2746
|
-
right:
|
|
2955
|
+
bottom: 16,
|
|
2956
|
+
right: 16,
|
|
2747
2957
|
borderRadius: "999px",
|
|
2748
2958
|
border: "none",
|
|
2749
2959
|
cursor: "pointer",
|
|
@@ -2753,30 +2963,30 @@ var styles = {
|
|
|
2753
2963
|
display: "flex",
|
|
2754
2964
|
alignItems: "center",
|
|
2755
2965
|
justifyContent: "center",
|
|
2756
|
-
fontSize:
|
|
2966
|
+
fontSize: 14,
|
|
2757
2967
|
fontWeight: 600,
|
|
2758
2968
|
zIndex: 99999,
|
|
2759
2969
|
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
|
|
2760
2970
|
},
|
|
2761
2971
|
floatingButtonClosed: {
|
|
2762
|
-
padding: "
|
|
2972
|
+
padding: "12px 20px",
|
|
2763
2973
|
gap: 8
|
|
2764
2974
|
},
|
|
2765
2975
|
floatingButtonOpen: {
|
|
2766
|
-
width:
|
|
2767
|
-
height:
|
|
2976
|
+
width: 52,
|
|
2977
|
+
height: 52,
|
|
2768
2978
|
padding: 0
|
|
2769
2979
|
},
|
|
2770
2980
|
floatingButtonMobile: {
|
|
2771
|
-
width:
|
|
2772
|
-
height:
|
|
2981
|
+
width: 52,
|
|
2982
|
+
height: 52,
|
|
2773
2983
|
padding: 0
|
|
2774
2984
|
},
|
|
2775
2985
|
// Panel (expandable)
|
|
2776
2986
|
panel: {
|
|
2777
2987
|
position: "fixed",
|
|
2778
|
-
bottom:
|
|
2779
|
-
right:
|
|
2988
|
+
bottom: 80,
|
|
2989
|
+
right: 16,
|
|
2780
2990
|
background: "#fff",
|
|
2781
2991
|
borderRadius: 16,
|
|
2782
2992
|
boxShadow: "0 20px 60px rgba(15, 23, 42, 0.3), 0 0 0 1px rgba(15, 23, 42, 0.05)",
|
|
@@ -2787,16 +2997,16 @@ var styles = {
|
|
|
2787
2997
|
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
|
|
2788
2998
|
},
|
|
2789
2999
|
panelNormal: {
|
|
2790
|
-
width:
|
|
2791
|
-
height:
|
|
3000
|
+
width: 360,
|
|
3001
|
+
height: 520
|
|
2792
3002
|
},
|
|
2793
3003
|
panelExpanded: {
|
|
2794
|
-
width:
|
|
2795
|
-
height:
|
|
3004
|
+
width: 480,
|
|
3005
|
+
height: 640
|
|
2796
3006
|
},
|
|
2797
3007
|
// Header with green gradient
|
|
2798
3008
|
header: {
|
|
2799
|
-
padding: "16px
|
|
3009
|
+
padding: "14px 16px",
|
|
2800
3010
|
background: "linear-gradient(135deg, #10b981, #059669)",
|
|
2801
3011
|
color: "#fff",
|
|
2802
3012
|
display: "flex",
|
|
@@ -2805,7 +3015,7 @@ var styles = {
|
|
|
2805
3015
|
},
|
|
2806
3016
|
title: {
|
|
2807
3017
|
margin: 0,
|
|
2808
|
-
fontSize:
|
|
3018
|
+
fontSize: 15,
|
|
2809
3019
|
fontWeight: 600,
|
|
2810
3020
|
letterSpacing: "-0.01em"
|
|
2811
3021
|
},
|
|
@@ -2818,8 +3028,8 @@ var styles = {
|
|
|
2818
3028
|
border: "none",
|
|
2819
3029
|
background: "rgba(255, 255, 255, 0.15)",
|
|
2820
3030
|
color: "#fff",
|
|
2821
|
-
width:
|
|
2822
|
-
height:
|
|
3031
|
+
width: 30,
|
|
3032
|
+
height: 30,
|
|
2823
3033
|
borderRadius: 8,
|
|
2824
3034
|
cursor: "pointer",
|
|
2825
3035
|
display: "flex",
|
|
@@ -2830,7 +3040,7 @@ var styles = {
|
|
|
2830
3040
|
// Messages area
|
|
2831
3041
|
messages: {
|
|
2832
3042
|
flex: 1,
|
|
2833
|
-
padding: "
|
|
3043
|
+
padding: "16px",
|
|
2834
3044
|
overflowY: "auto",
|
|
2835
3045
|
background: "#f8fafc",
|
|
2836
3046
|
display: "flex",
|
|
@@ -2845,10 +3055,10 @@ var styles = {
|
|
|
2845
3055
|
},
|
|
2846
3056
|
messageBubble: {
|
|
2847
3057
|
maxWidth: "85%",
|
|
2848
|
-
padding: "12px
|
|
3058
|
+
padding: "10px 12px",
|
|
2849
3059
|
borderRadius: 16,
|
|
2850
3060
|
lineHeight: 1.5,
|
|
2851
|
-
fontSize:
|
|
3061
|
+
fontSize: 13,
|
|
2852
3062
|
whiteSpace: "pre-wrap",
|
|
2853
3063
|
wordBreak: "break-word"
|
|
2854
3064
|
},
|
|
@@ -2962,7 +3172,7 @@ var styles = {
|
|
|
2962
3172
|
// Input area
|
|
2963
3173
|
inputWrapper: {
|
|
2964
3174
|
borderTop: "1px solid #e2e8f0",
|
|
2965
|
-
padding: "14px
|
|
3175
|
+
padding: "10px 14px",
|
|
2966
3176
|
display: "flex",
|
|
2967
3177
|
gap: 10,
|
|
2968
3178
|
alignItems: "flex-end",
|
|
@@ -2973,8 +3183,8 @@ var styles = {
|
|
|
2973
3183
|
resize: "none",
|
|
2974
3184
|
borderRadius: 12,
|
|
2975
3185
|
border: "1.5px solid #cbd5e1",
|
|
2976
|
-
padding: "10px
|
|
2977
|
-
fontSize:
|
|
3186
|
+
padding: "8px 10px",
|
|
3187
|
+
fontSize: 13,
|
|
2978
3188
|
fontFamily: "inherit",
|
|
2979
3189
|
lineHeight: 1.4,
|
|
2980
3190
|
transition: "border-color 0.2s"
|
|
@@ -2986,18 +3196,18 @@ var styles = {
|
|
|
2986
3196
|
sendButton: {
|
|
2987
3197
|
borderRadius: 12,
|
|
2988
3198
|
border: "none",
|
|
2989
|
-
padding: "
|
|
3199
|
+
padding: "8px 12px",
|
|
2990
3200
|
background: "linear-gradient(135deg, #10b981, #059669)",
|
|
2991
3201
|
color: "#fff",
|
|
2992
3202
|
cursor: "pointer",
|
|
2993
|
-
fontSize:
|
|
3203
|
+
fontSize: 13,
|
|
2994
3204
|
fontWeight: 600,
|
|
2995
3205
|
display: "flex",
|
|
2996
3206
|
alignItems: "center",
|
|
2997
3207
|
justifyContent: "center",
|
|
2998
3208
|
transition: "opacity 0.2s, transform 0.2s",
|
|
2999
|
-
minWidth:
|
|
3000
|
-
height:
|
|
3209
|
+
minWidth: 40,
|
|
3210
|
+
height: 40
|
|
3001
3211
|
},
|
|
3002
3212
|
// Status messages
|
|
3003
3213
|
statusNote: {
|
|
@@ -3027,42 +3237,42 @@ var FloatingChatBox = ({
|
|
|
3027
3237
|
open: openProp
|
|
3028
3238
|
}) => {
|
|
3029
3239
|
const isControlled = openProp !== void 0;
|
|
3030
|
-
const [internalOpen, setInternalOpen] = (0,
|
|
3240
|
+
const [internalOpen, setInternalOpen] = (0, import_react7.useState)(false);
|
|
3031
3241
|
const open = isControlled ? openProp : internalOpen;
|
|
3032
|
-
const setOpen = (0,
|
|
3242
|
+
const setOpen = (0, import_react7.useCallback)((value) => {
|
|
3033
3243
|
const newValue = typeof value === "function" ? value(open) : value;
|
|
3034
3244
|
if (!isControlled) {
|
|
3035
3245
|
setInternalOpen(newValue);
|
|
3036
3246
|
}
|
|
3037
3247
|
onOpenChange?.(newValue);
|
|
3038
3248
|
}, [isControlled, open, onOpenChange]);
|
|
3039
|
-
const [expanded, setExpanded] = (0,
|
|
3040
|
-
const [messages, setMessages] = (0,
|
|
3041
|
-
const [inputValue, setInputValue] = (0,
|
|
3042
|
-
const [conversationId, setConversationId] = (0,
|
|
3043
|
-
const [errorMessage, setErrorMessage] = (0,
|
|
3044
|
-
const [isFocused, setIsFocused] = (0,
|
|
3045
|
-
const [isMobile, setIsMobile] = (0,
|
|
3046
|
-
const messagesEndRef = (0,
|
|
3047
|
-
const messagesContainerRef = (0,
|
|
3048
|
-
const chatBoxRef = (0,
|
|
3049
|
-
const chatConfig = (0,
|
|
3249
|
+
const [expanded, setExpanded] = (0, import_react7.useState)(false);
|
|
3250
|
+
const [messages, setMessages] = (0, import_react7.useState)([]);
|
|
3251
|
+
const [inputValue, setInputValue] = (0, import_react7.useState)("");
|
|
3252
|
+
const [conversationId, setConversationId] = (0, import_react7.useState)();
|
|
3253
|
+
const [errorMessage, setErrorMessage] = (0, import_react7.useState)(null);
|
|
3254
|
+
const [isFocused, setIsFocused] = (0, import_react7.useState)(false);
|
|
3255
|
+
const [isMobile, setIsMobile] = (0, import_react7.useState)(false);
|
|
3256
|
+
const messagesEndRef = (0, import_react7.useRef)(null);
|
|
3257
|
+
const messagesContainerRef = (0, import_react7.useRef)(null);
|
|
3258
|
+
const chatBoxRef = (0, import_react7.useRef)(null);
|
|
3259
|
+
const chatConfig = (0, import_react7.useMemo)(() => {
|
|
3050
3260
|
if (!baseUrl) return void 0;
|
|
3051
3261
|
return { baseUrl, accessToken, getAccessToken };
|
|
3052
3262
|
}, [accessToken, baseUrl, getAccessToken]);
|
|
3053
3263
|
const { sendMessage: sendMessage2, isStreaming, streamingText, completeResponse } = useSendMessageStream(chatConfig);
|
|
3054
3264
|
const canSend = Boolean(mapId) && Boolean(baseUrl) && inputValue.trim().length > 0 && !isStreaming;
|
|
3055
|
-
(0,
|
|
3265
|
+
(0, import_react7.useEffect)(() => {
|
|
3056
3266
|
if (open && isMobile) {
|
|
3057
3267
|
setExpanded(true);
|
|
3058
3268
|
}
|
|
3059
3269
|
}, [open, isMobile]);
|
|
3060
|
-
const scrollToBottom = (0,
|
|
3270
|
+
const scrollToBottom = (0, import_react7.useCallback)(() => {
|
|
3061
3271
|
if (messagesEndRef.current) {
|
|
3062
3272
|
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
3063
3273
|
}
|
|
3064
3274
|
}, []);
|
|
3065
|
-
(0,
|
|
3275
|
+
(0, import_react7.useEffect)(() => {
|
|
3066
3276
|
if (open && messages.length === 0) {
|
|
3067
3277
|
setMessages([
|
|
3068
3278
|
{
|
|
@@ -3073,10 +3283,10 @@ var FloatingChatBox = ({
|
|
|
3073
3283
|
]);
|
|
3074
3284
|
}
|
|
3075
3285
|
}, [open, messages.length]);
|
|
3076
|
-
(0,
|
|
3286
|
+
(0, import_react7.useEffect)(() => {
|
|
3077
3287
|
scrollToBottom();
|
|
3078
3288
|
}, [messages, streamingText, scrollToBottom]);
|
|
3079
|
-
(0,
|
|
3289
|
+
(0, import_react7.useEffect)(() => {
|
|
3080
3290
|
if (!open) return;
|
|
3081
3291
|
if (isMobile && expanded) return;
|
|
3082
3292
|
const handleClickOutside = (event) => {
|
|
@@ -3089,7 +3299,7 @@ var FloatingChatBox = ({
|
|
|
3089
3299
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
3090
3300
|
};
|
|
3091
3301
|
}, [open, isMobile, expanded]);
|
|
3092
|
-
(0,
|
|
3302
|
+
(0, import_react7.useEffect)(() => {
|
|
3093
3303
|
if (typeof window === "undefined") return;
|
|
3094
3304
|
const mediaQuery = window.matchMedia("(max-width: 768px)");
|
|
3095
3305
|
const updateMobile = () => setIsMobile(mediaQuery.matches);
|
|
@@ -3107,7 +3317,7 @@ var FloatingChatBox = ({
|
|
|
3107
3317
|
}
|
|
3108
3318
|
};
|
|
3109
3319
|
}, []);
|
|
3110
|
-
(0,
|
|
3320
|
+
(0, import_react7.useEffect)(() => {
|
|
3111
3321
|
if (typeof document === "undefined") return;
|
|
3112
3322
|
if (!open || !isMobile) return;
|
|
3113
3323
|
document.body.style.overflow = "hidden";
|
|
@@ -3115,10 +3325,10 @@ var FloatingChatBox = ({
|
|
|
3115
3325
|
document.body.style.overflow = "";
|
|
3116
3326
|
};
|
|
3117
3327
|
}, [open, isMobile]);
|
|
3118
|
-
const addMessage = (0,
|
|
3328
|
+
const addMessage = (0, import_react7.useCallback)((message) => {
|
|
3119
3329
|
setMessages((prev) => [...prev, message]);
|
|
3120
3330
|
}, []);
|
|
3121
|
-
const handleSend = (0,
|
|
3331
|
+
const handleSend = (0, import_react7.useCallback)(async () => {
|
|
3122
3332
|
if (!mapId) {
|
|
3123
3333
|
setErrorMessage("Selecciona un mapa para usar el asistente.");
|
|
3124
3334
|
return;
|
|
@@ -3153,11 +3363,11 @@ var FloatingChatBox = ({
|
|
|
3153
3363
|
response
|
|
3154
3364
|
});
|
|
3155
3365
|
} catch (error) {
|
|
3156
|
-
setErrorMessage(
|
|
3366
|
+
setErrorMessage("Ocurri\xF3 un error al generar la respuesta.");
|
|
3157
3367
|
addMessage({
|
|
3158
3368
|
id: `error-${Date.now()}`,
|
|
3159
3369
|
role: "assistant",
|
|
3160
|
-
content:
|
|
3370
|
+
content: "\u274C Ocurri\xF3 un error al generar la respuesta."
|
|
3161
3371
|
});
|
|
3162
3372
|
}
|
|
3163
3373
|
}, [
|
|
@@ -3171,7 +3381,7 @@ var FloatingChatBox = ({
|
|
|
3171
3381
|
sendMessage2,
|
|
3172
3382
|
userId
|
|
3173
3383
|
]);
|
|
3174
|
-
const handleKeyDown = (0,
|
|
3384
|
+
const handleKeyDown = (0, import_react7.useCallback)(
|
|
3175
3385
|
(event) => {
|
|
3176
3386
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
3177
3387
|
event.preventDefault();
|
|
@@ -3182,20 +3392,20 @@ var FloatingChatBox = ({
|
|
|
3182
3392
|
},
|
|
3183
3393
|
[canSend, handleSend]
|
|
3184
3394
|
);
|
|
3185
|
-
const handleFollowUpClick = (0,
|
|
3395
|
+
const handleFollowUpClick = (0, import_react7.useCallback)((question) => {
|
|
3186
3396
|
setInputValue(question);
|
|
3187
3397
|
}, []);
|
|
3188
3398
|
const renderMetadata = (response) => {
|
|
3189
3399
|
if (!response?.metadata) return null;
|
|
3190
3400
|
const referencedLayers = response.metadata.referencedLayers;
|
|
3191
3401
|
if (!referencedLayers || referencedLayers.length === 0) return null;
|
|
3192
|
-
return /* @__PURE__ */ (0,
|
|
3193
|
-
/* @__PURE__ */ (0,
|
|
3194
|
-
/* @__PURE__ */ (0,
|
|
3402
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.metadataSection, children: [
|
|
3403
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.metadataTitle, children: [
|
|
3404
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LayersIcon, {}),
|
|
3195
3405
|
"Capas Analizadas"
|
|
3196
3406
|
] }),
|
|
3197
|
-
/* @__PURE__ */ (0,
|
|
3198
|
-
/* @__PURE__ */ (0,
|
|
3407
|
+
/* @__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: [
|
|
3408
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: layer.layerName }),
|
|
3199
3409
|
" (",
|
|
3200
3410
|
layer.featureCount,
|
|
3201
3411
|
" ",
|
|
@@ -3204,7 +3414,7 @@ var FloatingChatBox = ({
|
|
|
3204
3414
|
] }, index)) })
|
|
3205
3415
|
] });
|
|
3206
3416
|
};
|
|
3207
|
-
const handleActionClick = (0,
|
|
3417
|
+
const handleActionClick = (0, import_react7.useCallback)((action) => {
|
|
3208
3418
|
if (isStreaming) return;
|
|
3209
3419
|
setOpen(false);
|
|
3210
3420
|
requestAnimationFrame(() => {
|
|
@@ -3213,9 +3423,9 @@ var FloatingChatBox = ({
|
|
|
3213
3423
|
}, [isStreaming, setOpen, onActionClick]);
|
|
3214
3424
|
const renderActions = (response) => {
|
|
3215
3425
|
if (!response?.suggestedActions?.length) return null;
|
|
3216
|
-
return /* @__PURE__ */ (0,
|
|
3217
|
-
/* @__PURE__ */ (0,
|
|
3218
|
-
/* @__PURE__ */ (0,
|
|
3426
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.actionsSection, children: [
|
|
3427
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.sectionLabel, children: "Acciones Sugeridas" }),
|
|
3428
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.actionsGrid, children: response.suggestedActions.map((action, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3219
3429
|
"button",
|
|
3220
3430
|
{
|
|
3221
3431
|
type: "button",
|
|
@@ -3246,9 +3456,9 @@ var FloatingChatBox = ({
|
|
|
3246
3456
|
};
|
|
3247
3457
|
const renderFollowUps = (response) => {
|
|
3248
3458
|
if (!response?.followUpQuestions?.length) return null;
|
|
3249
|
-
return /* @__PURE__ */ (0,
|
|
3250
|
-
/* @__PURE__ */ (0,
|
|
3251
|
-
/* @__PURE__ */ (0,
|
|
3459
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.actionsSection, children: [
|
|
3460
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.sectionLabel, children: "Preguntas Relacionadas" }),
|
|
3461
|
+
/* @__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)(
|
|
3252
3462
|
"button",
|
|
3253
3463
|
{
|
|
3254
3464
|
type: "button",
|
|
@@ -3277,8 +3487,8 @@ var FloatingChatBox = ({
|
|
|
3277
3487
|
)) })
|
|
3278
3488
|
] });
|
|
3279
3489
|
};
|
|
3280
|
-
const chatContent = /* @__PURE__ */ (0,
|
|
3281
|
-
/* @__PURE__ */ (0,
|
|
3490
|
+
const chatContent = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.root, children: [
|
|
3491
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `
|
|
3282
3492
|
@keyframes zenitBlink {
|
|
3283
3493
|
0%, 49% { opacity: 1; }
|
|
3284
3494
|
50%, 100% { opacity: 0; }
|
|
@@ -3321,11 +3531,13 @@ var FloatingChatBox = ({
|
|
|
3321
3531
|
@media (max-width: 768px) {
|
|
3322
3532
|
.zenit-chat-panel.zenit-chat-panel--fullscreen {
|
|
3323
3533
|
position: fixed !important;
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3534
|
+
left: 0 !important;
|
|
3535
|
+
right: 0 !important;
|
|
3536
|
+
top: 4rem !important;
|
|
3537
|
+
bottom: 0 !important;
|
|
3538
|
+
width: 100% !important;
|
|
3539
|
+
max-width: 100% !important;
|
|
3540
|
+
height: auto !important;
|
|
3329
3541
|
border-radius: 0 !important;
|
|
3330
3542
|
display: flex !important;
|
|
3331
3543
|
flex-direction: column !important;
|
|
@@ -3348,7 +3560,7 @@ var FloatingChatBox = ({
|
|
|
3348
3560
|
}
|
|
3349
3561
|
}
|
|
3350
3562
|
` }),
|
|
3351
|
-
open && /* @__PURE__ */ (0,
|
|
3563
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3352
3564
|
"div",
|
|
3353
3565
|
{
|
|
3354
3566
|
ref: chatBoxRef,
|
|
@@ -3358,10 +3570,10 @@ var FloatingChatBox = ({
|
|
|
3358
3570
|
...expanded ? styles.panelExpanded : styles.panelNormal
|
|
3359
3571
|
},
|
|
3360
3572
|
children: [
|
|
3361
|
-
/* @__PURE__ */ (0,
|
|
3362
|
-
/* @__PURE__ */ (0,
|
|
3363
|
-
/* @__PURE__ */ (0,
|
|
3364
|
-
/* @__PURE__ */ (0,
|
|
3573
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("header", { style: styles.header, children: [
|
|
3574
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { style: styles.title, children: "Asistente Zenit AI" }),
|
|
3575
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.headerButtons, children: [
|
|
3576
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3365
3577
|
"button",
|
|
3366
3578
|
{
|
|
3367
3579
|
type: "button",
|
|
@@ -3374,10 +3586,10 @@ var FloatingChatBox = ({
|
|
|
3374
3586
|
e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
|
|
3375
3587
|
},
|
|
3376
3588
|
"aria-label": expanded ? "Contraer" : "Expandir",
|
|
3377
|
-
children: expanded ? /* @__PURE__ */ (0,
|
|
3589
|
+
children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CollapseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ExpandIcon, {})
|
|
3378
3590
|
}
|
|
3379
3591
|
),
|
|
3380
|
-
/* @__PURE__ */ (0,
|
|
3592
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3381
3593
|
"button",
|
|
3382
3594
|
{
|
|
3383
3595
|
type: "button",
|
|
@@ -3390,20 +3602,20 @@ var FloatingChatBox = ({
|
|
|
3390
3602
|
e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
|
|
3391
3603
|
},
|
|
3392
3604
|
"aria-label": "Cerrar",
|
|
3393
|
-
children: /* @__PURE__ */ (0,
|
|
3605
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {})
|
|
3394
3606
|
}
|
|
3395
3607
|
)
|
|
3396
3608
|
] })
|
|
3397
3609
|
] }),
|
|
3398
|
-
/* @__PURE__ */ (0,
|
|
3399
|
-
messages.map((message) => /* @__PURE__ */ (0,
|
|
3610
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { ref: messagesContainerRef, className: "zenit-ai-body", style: styles.messages, children: [
|
|
3611
|
+
messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3400
3612
|
"div",
|
|
3401
3613
|
{
|
|
3402
3614
|
style: {
|
|
3403
3615
|
...styles.messageWrapper,
|
|
3404
3616
|
alignItems: message.role === "user" ? "flex-end" : "flex-start"
|
|
3405
3617
|
},
|
|
3406
|
-
children: /* @__PURE__ */ (0,
|
|
3618
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3407
3619
|
"div",
|
|
3408
3620
|
{
|
|
3409
3621
|
style: {
|
|
@@ -3411,7 +3623,7 @@ var FloatingChatBox = ({
|
|
|
3411
3623
|
...message.role === "user" ? styles.userMessage : styles.assistantMessage
|
|
3412
3624
|
},
|
|
3413
3625
|
children: [
|
|
3414
|
-
message.role === "assistant" ? /* @__PURE__ */ (0,
|
|
3626
|
+
message.role === "assistant" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MarkdownRenderer, { content: message.content }) : message.content,
|
|
3415
3627
|
message.role === "assistant" && renderMetadata(message.response),
|
|
3416
3628
|
message.role === "assistant" && renderActions(message.response),
|
|
3417
3629
|
message.role === "assistant" && renderFollowUps(message.response)
|
|
@@ -3421,39 +3633,39 @@ var FloatingChatBox = ({
|
|
|
3421
3633
|
},
|
|
3422
3634
|
message.id
|
|
3423
3635
|
)),
|
|
3424
|
-
isStreaming && /* @__PURE__ */ (0,
|
|
3636
|
+
isStreaming && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3425
3637
|
"div",
|
|
3426
3638
|
{
|
|
3427
3639
|
style: {
|
|
3428
3640
|
...styles.messageWrapper,
|
|
3429
3641
|
alignItems: "flex-start"
|
|
3430
3642
|
},
|
|
3431
|
-
children: /* @__PURE__ */ (0,
|
|
3643
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3432
3644
|
"div",
|
|
3433
3645
|
{
|
|
3434
3646
|
style: {
|
|
3435
3647
|
...styles.messageBubble,
|
|
3436
3648
|
...styles.assistantMessage
|
|
3437
3649
|
},
|
|
3438
|
-
children: streamingText ? /* @__PURE__ */ (0,
|
|
3439
|
-
/* @__PURE__ */ (0,
|
|
3440
|
-
/* @__PURE__ */ (0,
|
|
3441
|
-
] }) : /* @__PURE__ */ (0,
|
|
3442
|
-
/* @__PURE__ */ (0,
|
|
3443
|
-
/* @__PURE__ */ (0,
|
|
3444
|
-
/* @__PURE__ */ (0,
|
|
3445
|
-
/* @__PURE__ */ (0,
|
|
3446
|
-
/* @__PURE__ */ (0,
|
|
3650
|
+
children: streamingText ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
3651
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MarkdownRenderer, { content: streamingText }),
|
|
3652
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.cursor })
|
|
3653
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.thinkingText, children: [
|
|
3654
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Pensando" }),
|
|
3655
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.typingIndicator, children: [
|
|
3656
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
|
|
3657
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
|
|
3658
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot })
|
|
3447
3659
|
] })
|
|
3448
3660
|
] })
|
|
3449
3661
|
}
|
|
3450
3662
|
)
|
|
3451
3663
|
}
|
|
3452
3664
|
),
|
|
3453
|
-
/* @__PURE__ */ (0,
|
|
3665
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: messagesEndRef })
|
|
3454
3666
|
] }),
|
|
3455
|
-
/* @__PURE__ */ (0,
|
|
3456
|
-
/* @__PURE__ */ (0,
|
|
3667
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "zenit-ai-input-area", style: styles.inputWrapper, children: [
|
|
3668
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3457
3669
|
"textarea",
|
|
3458
3670
|
{
|
|
3459
3671
|
style: {
|
|
@@ -3470,7 +3682,7 @@ var FloatingChatBox = ({
|
|
|
3470
3682
|
disabled: !mapId || !baseUrl || isStreaming
|
|
3471
3683
|
}
|
|
3472
3684
|
),
|
|
3473
|
-
/* @__PURE__ */ (0,
|
|
3685
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3474
3686
|
"button",
|
|
3475
3687
|
{
|
|
3476
3688
|
type: "button",
|
|
@@ -3479,36 +3691,38 @@ var FloatingChatBox = ({
|
|
|
3479
3691
|
onClick: () => void handleSend(),
|
|
3480
3692
|
disabled: !canSend,
|
|
3481
3693
|
"aria-label": "Enviar mensaje",
|
|
3482
|
-
children: /* @__PURE__ */ (0,
|
|
3694
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SendIcon, {})
|
|
3483
3695
|
}
|
|
3484
3696
|
)
|
|
3485
3697
|
] }),
|
|
3486
|
-
errorMessage && /* @__PURE__ */ (0,
|
|
3487
|
-
|
|
3488
|
-
!
|
|
3698
|
+
errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.errorText, children: errorMessage }),
|
|
3699
|
+
isStreaming && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.statusNote, children: "Generando sugerencias..." }),
|
|
3700
|
+
!mapId && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.statusNote, children: "Selecciona un mapa para usar el asistente" }),
|
|
3701
|
+
!baseUrl && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.statusNote, children: "Configura la baseUrl del SDK" })
|
|
3489
3702
|
]
|
|
3490
3703
|
}
|
|
3491
3704
|
),
|
|
3492
|
-
!(hideButton && !open) && /* @__PURE__ */ (0,
|
|
3705
|
+
!(hideButton && !open) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3493
3706
|
"button",
|
|
3494
3707
|
{
|
|
3495
3708
|
type: "button",
|
|
3496
3709
|
className: `zenit-ai-button ${open ? "open" : ""}${open && isMobile ? " zenit-ai-button--hidden-mobile" : ""}`,
|
|
3497
3710
|
style: {
|
|
3498
3711
|
...styles.floatingButton,
|
|
3499
|
-
...open ? styles.floatingButtonOpen : isMobile ? styles.floatingButtonMobile : styles.floatingButtonClosed
|
|
3712
|
+
...open ? styles.floatingButtonOpen : isMobile ? styles.floatingButtonMobile : styles.floatingButtonClosed,
|
|
3713
|
+
zIndex: open ? 100001 : 99999
|
|
3500
3714
|
},
|
|
3501
3715
|
onClick: () => setOpen((prev) => !prev),
|
|
3502
3716
|
"aria-label": open ? "Cerrar asistente" : "Abrir asistente Zenit AI",
|
|
3503
|
-
children: open ? /* @__PURE__ */ (0,
|
|
3504
|
-
/* @__PURE__ */ (0,
|
|
3505
|
-
!isMobile && /* @__PURE__ */ (0,
|
|
3717
|
+
children: open ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
3718
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChatIcon, {}),
|
|
3719
|
+
!isMobile && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Asistente IA" })
|
|
3506
3720
|
] })
|
|
3507
3721
|
}
|
|
3508
3722
|
)
|
|
3509
3723
|
] });
|
|
3510
3724
|
if (typeof document !== "undefined") {
|
|
3511
|
-
return (0,
|
|
3725
|
+
return (0, import_react_dom2.createPortal)(chatContent, document.body);
|
|
3512
3726
|
}
|
|
3513
3727
|
return chatContent;
|
|
3514
3728
|
};
|