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.
@@ -58,9 +58,9 @@ __export(react_exports, {
58
58
  module.exports = __toCommonJS(react_exports);
59
59
 
60
60
  // src/react/ZenitMap.tsx
61
- var import_react = __toESM(require("react"));
62
- var import_react_leaflet = require("react-leaflet");
63
- var import_leaflet = __toESM(require("leaflet"));
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: 10,
257
- maxZoom: 17,
258
- minFactor: 0.6,
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/ZenitMap.tsx
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 DEFAULT_CENTER = [0, 0];
298
- var DEFAULT_ZOOM = 3;
299
- function computeBBoxFromGeojson(geojson) {
300
- if (!geojson) return null;
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 mergeBBoxes(bboxes) {
326
- const valid = bboxes.filter((bbox) => !!bbox);
327
- if (valid.length === 0) return null;
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 getFeatureLayerId(feature) {
340
- const layerId = feature?.properties?.__zenit_layerId ?? feature?.properties?.layerId ?? feature?.properties?.layer_id;
341
- if (layerId === void 0 || layerId === null) return null;
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 escapeHtml(value) {
345
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
312
+ function buildFeatureCollection(features) {
313
+ return {
314
+ type: "FeatureCollection",
315
+ features
316
+ };
346
317
  }
347
- var DESCRIPTION_KEYS = /* @__PURE__ */ new Set(["descripcion", "description"]);
348
- var POPUP_EXCLUDED_KEYS = /* @__PURE__ */ new Set(["geom", "geometry"]);
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 DESKTOP_POPUP_DIMENSIONS = { maxWidth: 350, minWidth: 280, maxHeight: 480 };
351
- var MOBILE_POPUP_DIMENSIONS = { maxWidth: 280, minWidth: 240, maxHeight: 380 };
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
- /* ===== Zenit Leaflet Popup - Modern Professional Styling ===== */
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
- overflow: hidden;
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
- /* Content area with scroll support */
368
- .zenit-leaflet-popup .leaflet-popup-content {
453
+ .custom-leaflet-popup .leaflet-popup-content {
369
454
  margin: 0;
370
- padding: 0;
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
- /* Value styling - darker, readable */
454
- .zenit-popup-value {
455
- font-size: 13px;
456
- font-weight: 400;
457
- color: #1f2937;
458
- overflow-wrap: break-word;
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
- /* Empty state styling */
500
- .zenit-popup-empty {
501
- font-size: 13px;
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
- /* Webkit scrollbar styling */
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
- .zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-track {
514
- background: transparent;
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
- .zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb {
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
- .zenit-leaflet-popup .leaflet-popup-content-wrapper {
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
- .zenit-popup-row.zenit-popup-description .zenit-popup-value {
575
- font-size: 12px;
576
- max-height: 120px;
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" || typeof window.matchMedia !== "function") {
544
+ if (typeof window === "undefined") {
616
545
  return DESKTOP_POPUP_DIMENSIONS;
617
546
  }
618
- return window.matchMedia("(max-width: 640px)").matches ? MOBILE_POPUP_DIMENSIONS : DESKTOP_POPUP_DIMENSIONS;
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 normalizeDescriptionValue(value) {
621
- if (value === void 0 || value === null) return null;
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
638
555
  }
639
- function safeJsonStringify(value) {
640
- try {
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
- return '<span class="zenit-popup-empty">Sin datos</span>';
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
- const json = safeJsonStringify(value);
653
- return `<pre class="zenit-popup-pre">${escapeHtml(json)}</pre>`;
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 `<span>${escapeHtml(String(value))}</span>`;
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 entries = Object.entries(properties).filter(
676
- ([key, value]) => shouldIncludePopupEntry(key, value)
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 `<div class="zenit-popup-card"><div class="zenit-popup-empty">Sin datos disponibles</div></div>`;
609
+ return '<div style="padding:8px 0; color:#64748b; text-align:center;">Sin datos disponibles</div>';
680
610
  }
681
- const descriptionEntry = entries.find(([key]) => isDescriptionKey(key));
682
- const otherEntries = entries.filter(([key]) => !isDescriptionKey(key));
683
- let rowsHtml = "";
684
- if (descriptionEntry) {
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
- rowsHtml += `
689
- <div class="zenit-popup-row zenit-popup-description">
690
- <div class="zenit-popup-label">${label}</div>
691
- <div class="zenit-popup-value">${valueHtml}</div>
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
- rowsHtml += otherEntries.map(([key, value]) => {
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 withAlpha(color, alpha) {
708
- const trimmed = color.trim();
709
- if (trimmed.startsWith("#")) {
710
- const hex = trimmed.replace("#", "");
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
- function getRgbFromColor(color) {
730
- const trimmed = color.trim();
731
- if (trimmed.startsWith("#")) {
732
- const hex = trimmed.replace("#", "");
733
- const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
734
- if (expanded.length === 6) {
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
- const rgbMatch = trimmed.match(/rgba?\(([^)]+)\)/i);
742
- if (rgbMatch) {
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 getLabelTextStyles(color) {
751
- const rgb = getRgbFromColor(color);
752
- if (!rgb) {
753
- return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.6)" };
754
- }
755
- const luminance = (0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b) / 255;
756
- if (luminance > 0.6) {
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 FitToBounds = ({ bbox }) => {
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, import_react.useState)(null);
923
- const [layers, setLayers] = (0, import_react.useState)([]);
924
- const [effectiveStates, setEffectiveStates] = (0, import_react.useState)([]);
925
- const [loadingMap, setLoadingMap] = (0, import_react.useState)(false);
926
- const [mapError, setMapError] = (0, import_react.useState)(null);
927
- const [mapInstance, setMapInstance] = (0, import_react.useState)(null);
928
- const [panesReady, setPanesReady] = (0, import_react.useState)(false);
929
- const [currentZoom, setCurrentZoom] = (0, import_react.useState)(initialZoom ?? DEFAULT_ZOOM);
930
- const [isMobile, setIsMobile] = (0, import_react.useState)(() => {
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, import_react.useMemo)(() => normalizeMapLayers(map), [map]);
935
- (0, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
1176
+ (0, import_react4.useEffect)(() => {
954
1177
  if (featureInfoMode === "popup") {
955
1178
  ensurePopupStyles();
956
1179
  }
957
1180
  }, [featureInfoMode]);
958
- const layerStyleIndex = (0, import_react.useMemo)(() => {
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, import_react.useMemo)(() => {
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, import_react.useMemo)(() => {
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, import_react.useMemo)(() => {
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 [baseStates, setBaseStates] = (0, import_react.useState)([]);
1009
- const [mapOverrides, setMapOverrides] = (0, import_react.useState)([]);
1010
- const [controlOverrides, setControlOverrides] = (0, import_react.useState)([]);
1011
- const [uiOverrides, setUiOverrides] = (0, import_react.useState)([]);
1012
- (0, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
1340
+ (0, import_react4.useEffect)(() => {
1089
1341
  if (layerStates) {
1090
1342
  setEffectiveStates(layerStates);
1091
1343
  }
1092
1344
  }, [layerStates]);
1093
- (0, import_react.useEffect)(() => {
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, import_react.useEffect)(() => {
1358
+ (0, import_react4.useEffect)(() => {
1107
1359
  if (!Array.isArray(layerControls) || layerControls.length > 0) return;
1108
1360
  setUiOverrides([]);
1109
1361
  }, [layerControls]);
1110
- (0, import_react.useEffect)(() => {
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, import_react.useCallback)(
1382
+ const updateOpacityFromUi = (0, import_react4.useCallback)(
1131
1383
  (layerId, uiOpacity) => {
1132
1384
  const meta = layerMetaIndex.get(String(layerId));
1133
- const zoomFactor = getLayerZoomOpacityFactor(
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, import_react.useMemo)(() => {
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, import_react.useEffect)(() => {
1432
+ (0, import_react4.useEffect)(() => {
1186
1433
  setCurrentZoom(zoom);
1187
1434
  }, [zoom]);
1188
- const decoratedLayers = (0, import_react.useMemo)(() => {
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, import_react.useMemo)(() => {
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 explicitZoomBBox = (0, import_react.useMemo)(() => {
1199
- if (zoomToBbox) return zoomToBbox;
1200
- if (zoomToGeojson) return computeBBoxFromGeojson(zoomToGeojson);
1201
- return null;
1202
- }, [zoomToBbox, zoomToGeojson]);
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, import_react.useMemo)(() => {
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 opacity = layerState.effective?.opacity ?? 1;
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, import_react.useCallback)(
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
- const labelPane = targetMap.getPane(labelPaneName) ?? targetMap.createPane(labelPaneName);
1255
- fillPane.style.zIndex = String(baseZIndex + order);
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, import_react.useCallback)(
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, import_react.useEffect)(() => {
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}-labels`);
1285
- if (testPane) {
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, import_react.useMemo)(() => {
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 import_leaflet.default.CircleMarker;
1294
- const originalStyle = layer instanceof import_leaflet.default.Path ? {
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 import_leaflet.default.CircleMarker ? layer.getRadius() : null;
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: "zenit-leaflet-popup",
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 candidates = response.data?.features ?? [];
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 import_leaflet.default.Path && originalStyle) {
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 import_leaflet.default.CircleMarker && typeof originalRadius === "number") {
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 import_leaflet.default.Path && originalStyle) {
1619
+ if (layer instanceof import_leaflet4.default.Path && originalStyle) {
1373
1620
  layer.setStyle(originalStyle);
1374
1621
  }
1375
- if (layer instanceof import_leaflet.default.CircleMarker && typeof originalRadius === "number") {
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
- const sanitizedBaseOpacity = clampOpacity3(baseOpacity);
1388
- const normalizedStyleFill = typeof resolvedStyle?.fillOpacity === "number" ? clampOpacity3(resolvedStyle.fillOpacity) : 0.8;
1389
- const effectiveOpacity = getEffectiveLayerOpacity(
1390
- sanitizedBaseOpacity,
1391
- currentZoom,
1392
- resolvedLayerType,
1393
- geometryType
1394
- );
1395
- const fillOpacity = clampOpacity3(effectiveOpacity * normalizedStyleFill);
1396
- const strokeOpacity = clampOpacity3(Math.max(0.35, effectiveOpacity * 0.9));
1397
- return {
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
- const buildLabelIcon = (0, import_react.useCallback)((label, opacity, color) => {
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, import_jsx_runtime.jsx)("div", { style: { padding: 16, height, width }, children: "Cargando mapa..." });
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, import_jsx_runtime.jsxs)("div", { style: { padding: 16, height, width, color: "red" }, children: [
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, import_jsx_runtime.jsxs)(
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, import_jsx_runtime.jsx)("div", { style: { flex: 1, position: "relative" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1539
- import_react_leaflet.MapContainer,
1725
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1726
+ "div",
1540
1727
  {
1541
- center,
1542
- zoom,
1543
- style: { height: "100%", width: "100%" },
1544
- scrollWheelZoom: true,
1545
- zoomControl: false,
1546
- children: [
1547
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1548
- import_react_leaflet.TileLayer,
1549
- {
1550
- url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
1551
- attribution: "\xA9 OpenStreetMap contributors"
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
- data: fillData,
1575
- pane: panesReady && mapInstance?.getPane(fillPaneName) ? fillPaneName : void 0,
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
- pointsData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1581
- import_react_leaflet.GeoJSON,
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
- data: pointsData,
1584
- pane: panesReady && mapInstance?.getPane(pointsPaneName) ? pointsPaneName : void 0,
1585
- pointToLayer: (feature, latlng) => import_leaflet.default.circleMarker(latlng, {
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
- panesReady && mapInstance?.getPane(labelPaneName) ? labelMarkers.filter(
1593
- (marker) => String(marker.layerId) === String(layerState.mapLayer.layerId)
1594
- ).map((marker) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1595
- import_react_leaflet.Marker,
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
- position: marker.position,
1598
- icon: buildLabelIcon(marker.label, marker.opacity, marker.color),
1599
- interactive: false,
1600
- pane: labelPaneName
1601
- },
1602
- marker.key
1603
- )) : null
1604
- ] }, layerState.mapLayer.layerId.toString());
1605
- }),
1606
- overlayGeojson && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1607
- import_react_leaflet.GeoJSON,
1608
- {
1609
- data: overlayGeojson,
1610
- style: overlayStyleFunction,
1611
- onEachFeature: overlayOnEachFeature
1612
- },
1613
- "zenit-overlay-geojson"
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, import_jsx_runtime.jsxs)(
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, import_jsx_runtime.jsx)("div", { style: { fontWeight: 600, marginBottom: 4 }, children: "Overlay activo" }),
1645
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 13 }, children: [
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, import_jsx_runtime.jsx)("div", { style: { fontWeight: 600, marginBottom: 12 }, children: "Capas" }),
1654
- decoratedLayers.map((layerState) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
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, import_jsx_runtime.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
1660
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
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, import_jsx_runtime.jsx)("span", { children: layerState.layer?.name ?? `Capa ${layerState.mapLayer.layerId}` })
1881
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: layerState.layer?.name ?? `Capa ${layerState.mapLayer.layerId}` })
1672
1882
  ] }),
1673
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: 8 }, children: [
1674
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 4 }, children: [
1675
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "#4a5568" }, children: "Opacidad" }),
1676
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
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, import_jsx_runtime.jsx)(
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 import_react2 = __toESM(require("react"));
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 import_jsx_runtime2 = require("react/jsx-runtime");
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, import_react2.useState)(null);
1758
- const [loadingMap, setLoadingMap] = (0, import_react2.useState)(false);
1759
- const [mapError, setMapError] = (0, import_react2.useState)(null);
1760
- const [layers, setLayers] = (0, import_react2.useState)([]);
1761
- const [activeTab, setActiveTab] = (0, import_react2.useState)("layers");
1762
- const [panelVisible, setPanelVisible] = (0, import_react2.useState)(true);
1763
- const lastEmittedStatesRef = (0, import_react2.useRef)(null);
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, import_react2.useMemo)(
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, import_react2.useMemo)(
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, import_react2.useMemo)(
1996
+ const effectiveStates = (0, import_react5.useMemo)(
1787
1997
  () => layerStates ?? applyLayerOverrides(baseStates, overrideStates),
1788
1998
  [baseStates, layerStates, overrideStates]
1789
1999
  );
1790
- const layerMetaIndex = (0, import_react2.useMemo)(() => {
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 = import_react2.default.useCallback((state) => {
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 = import_react2.default.useCallback(
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, import_react2.useMemo)(() => {
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, import_react2.useEffect)(() => {
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, import_react2.useEffect)(() => {
2084
+ (0, import_react5.useEffect)(() => {
1875
2085
  if (!showUploadTab && activeTab === "upload") {
1876
2086
  setActiveTab("layers");
1877
2087
  }
1878
2088
  }, [activeTab, showUploadTab]);
1879
- (0, import_react2.useEffect)(() => {
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 = import_react2.default.useCallback(
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 = import_react2.default.useCallback(
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 = import_react2.default.useCallback(
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, import_react2.useMemo)(() => {
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 = import_react2.default.useCallback(
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, import_jsx_runtime2.jsx)("div", { className, style: panelStyle, children: "Cargando capas\u2026" });
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, import_jsx_runtime2.jsxs)("div", { className, style: { ...panelStyle, color: "#c53030" }, children: [
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, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: decoratedLayers.map((layerState) => {
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, import_jsx_runtime2.jsxs)(
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, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
2033
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: 10, alignItems: "flex-start", minWidth: 0, flex: 1 }, children: [
2034
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
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, import_jsx_runtime2.jsx)(
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, import_jsx_runtime2.jsx)(import_lucide_react.Eye, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.EyeOff, { size: 16 })
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, import_jsx_runtime2.jsxs)("div", { style: { minWidth: 0, flex: 1 }, children: [
2064
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
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, import_jsx_runtime2.jsxs)("div", { style: { color: muted ? "#94a3b8" : "#64748b", fontSize: 12 }, children: [
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, import_jsx_runtime2.jsx)("div", { style: { display: "flex", alignItems: "flex-start", gap: 6, flexShrink: 0 }, children: typeof featureCount === "number" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "zlm-badge", children: [
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, import_jsx_runtime2.jsx)("div", { style: { display: "flex", gap: 10, alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { flex: 1 }, children: [
2094
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 6, color: "#64748b", fontSize: 12 }, children: [
2095
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Opacidad" }),
2096
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
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, import_jsx_runtime2.jsx)(
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, import_jsx_runtime2.jsxs)("div", { className: ["zenit-layer-manager", className].filter(Boolean).join(" "), style: panelStyle, children: [
2140
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: `
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, import_jsx_runtime2.jsxs)("div", { style: headerStyle, children: [
2236
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
2237
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
2238
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontWeight: 800, fontSize: 16, color: "#0f172a" }, children: "Gesti\xF3n de Capas" }),
2239
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { color: "#64748b", fontSize: 12 }, children: [
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, import_jsx_runtime2.jsxs)(
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, import_jsx_runtime2.jsx)(import_lucide_react.Eye, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.EyeOff, { size: 16 }),
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, import_jsx_runtime2.jsxs)(
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, import_jsx_runtime2.jsxs)(
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, import_jsx_runtime2.jsx)(import_lucide_react.Layers, { size: 16 }),
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, import_jsx_runtime2.jsxs)(
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, import_jsx_runtime2.jsx)(import_lucide_react.Upload, { size: 16 }),
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, import_jsx_runtime2.jsxs)("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
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, import_jsx_runtime2.jsx)("div", { style: { color: "#475569", fontSize: 13 }, children: "Pr\xF3ximamente podr\xE1s subir capas desde este panel." })
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 import_jsx_runtime3 = require("react/jsx-runtime");
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, import_jsx_runtime3.jsxs)(
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, import_jsx_runtime3.jsxs)("header", { style: { marginBottom: 12 }, children: [
2329
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { style: { margin: 0, fontSize: 16 }, children: title }),
2330
- description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: { margin: "6px 0 0", color: "#475569", fontSize: 13 }, children: description })
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, import_jsx_runtime3.jsx)("div", { children })
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 import_react4 = require("react");
2340
- var import_react_dom = require("react-dom");
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 import_react3 = require("react");
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, import_react3.useState)(false);
2476
- const [error, setError] = (0, import_react3.useState)(null);
2477
- const send = (0, import_react3.useCallback)(
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, import_react3.useState)(false);
2496
- const [streamingText, setStreamingText] = (0, import_react3.useState)("");
2497
- const [completeResponse, setCompleteResponse] = (0, import_react3.useState)(null);
2498
- const [error, setError] = (0, import_react3.useState)(null);
2499
- const requestIdRef = (0, import_react3.useRef)(0);
2500
- const reset = (0, import_react3.useCallback)(() => {
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, import_react3.useCallback)(
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 import_jsx_runtime4 = require("react/jsx-runtime");
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, import_jsx_runtime4.jsx)("div", { className, style: { wordBreak: "break-word" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)("h1", { style: { fontSize: "1.5em", fontWeight: 700, marginTop: "1em", marginBottom: "0.5em" }, ...props, children }),
2583
- h2: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { style: { fontSize: "1.3em", fontWeight: 700, marginTop: "0.9em", marginBottom: "0.45em" }, ...props, children }),
2584
- h3: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { style: { fontSize: "1.15em", fontWeight: 600, marginTop: "0.75em", marginBottom: "0.4em" }, ...props, children }),
2585
- h4: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h4", { style: { fontSize: "1.05em", fontWeight: 600, marginTop: "0.6em", marginBottom: "0.35em" }, ...props, children }),
2586
- h5: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h5", { style: { fontSize: "1em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
2587
- h6: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h6", { style: { fontSize: "0.95em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
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, import_jsx_runtime4.jsx)("p", { style: { marginTop: "0.5em", marginBottom: "0.5em", lineHeight: 1.6 }, ...props, children }),
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, import_jsx_runtime4.jsx)("ul", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
2592
- ol: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ol", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
2593
- li: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { style: { marginTop: "0.25em", marginBottom: "0.25em" }, ...props, children }),
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, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)("pre", { style: { margin: 0 }, ...props, children }),
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, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)("strong", { style: { fontWeight: 600 }, ...props, children }),
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, import_jsx_runtime4.jsx)("em", { style: { fontStyle: "italic" }, ...props, children }),
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, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)("div", { style: { overflowX: "auto", marginTop: "0.5em", marginBottom: "0.5em" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)(
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, import_jsx_runtime4.jsx)(
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 import_jsx_runtime5 = require("react/jsx-runtime");
2712
- var ChatIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
2713
- var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2714
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2715
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
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, import_jsx_runtime5.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2718
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "15 3 21 3 21 9" }),
2719
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "9 21 3 21 3 15" }),
2720
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
2721
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
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, import_jsx_runtime5.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2724
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "4 14 10 14 10 20" }),
2725
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "20 10 14 10 14 4" }),
2726
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
2727
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
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, import_jsx_runtime5.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2730
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
2731
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
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, import_jsx_runtime5.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2734
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
2735
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "2 17 12 22 22 17" }),
2736
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "2 12 12 17 22 12" })
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: 24,
2746
- right: 24,
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: 15,
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: "14px 24px",
2972
+ padding: "12px 20px",
2763
2973
  gap: 8
2764
2974
  },
2765
2975
  floatingButtonOpen: {
2766
- width: 56,
2767
- height: 56,
2976
+ width: 52,
2977
+ height: 52,
2768
2978
  padding: 0
2769
2979
  },
2770
2980
  floatingButtonMobile: {
2771
- width: 56,
2772
- height: 56,
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: 92,
2779
- right: 24,
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: 400,
2791
- height: 550
3000
+ width: 360,
3001
+ height: 520
2792
3002
  },
2793
3003
  panelExpanded: {
2794
- width: 520,
2795
- height: 700
3004
+ width: 480,
3005
+ height: 640
2796
3006
  },
2797
3007
  // Header with green gradient
2798
3008
  header: {
2799
- padding: "16px 18px",
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: 16,
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: 32,
2822
- height: 32,
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: "20px 18px",
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 14px",
3058
+ padding: "10px 12px",
2849
3059
  borderRadius: 16,
2850
3060
  lineHeight: 1.5,
2851
- fontSize: 14,
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 16px",
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 12px",
2977
- fontSize: 14,
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: "10px 14px",
3199
+ padding: "8px 12px",
2990
3200
  background: "linear-gradient(135deg, #10b981, #059669)",
2991
3201
  color: "#fff",
2992
3202
  cursor: "pointer",
2993
- fontSize: 14,
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: 44,
3000
- height: 44
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, import_react4.useState)(false);
3240
+ const [internalOpen, setInternalOpen] = (0, import_react7.useState)(false);
3031
3241
  const open = isControlled ? openProp : internalOpen;
3032
- const setOpen = (0, import_react4.useCallback)((value) => {
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, import_react4.useState)(false);
3040
- const [messages, setMessages] = (0, import_react4.useState)([]);
3041
- const [inputValue, setInputValue] = (0, import_react4.useState)("");
3042
- const [conversationId, setConversationId] = (0, import_react4.useState)();
3043
- const [errorMessage, setErrorMessage] = (0, import_react4.useState)(null);
3044
- const [isFocused, setIsFocused] = (0, import_react4.useState)(false);
3045
- const [isMobile, setIsMobile] = (0, import_react4.useState)(false);
3046
- const messagesEndRef = (0, import_react4.useRef)(null);
3047
- const messagesContainerRef = (0, import_react4.useRef)(null);
3048
- const chatBoxRef = (0, import_react4.useRef)(null);
3049
- const chatConfig = (0, import_react4.useMemo)(() => {
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, import_react4.useEffect)(() => {
3265
+ (0, import_react7.useEffect)(() => {
3056
3266
  if (open && isMobile) {
3057
3267
  setExpanded(true);
3058
3268
  }
3059
3269
  }, [open, isMobile]);
3060
- const scrollToBottom = (0, import_react4.useCallback)(() => {
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, import_react4.useEffect)(() => {
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, import_react4.useEffect)(() => {
3286
+ (0, import_react7.useEffect)(() => {
3077
3287
  scrollToBottom();
3078
3288
  }, [messages, streamingText, scrollToBottom]);
3079
- (0, import_react4.useEffect)(() => {
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, import_react4.useEffect)(() => {
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, import_react4.useEffect)(() => {
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, import_react4.useCallback)((message) => {
3328
+ const addMessage = (0, import_react7.useCallback)((message) => {
3119
3329
  setMessages((prev) => [...prev, message]);
3120
3330
  }, []);
3121
- const handleSend = (0, import_react4.useCallback)(async () => {
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(error instanceof Error ? error.message : "Ocurri\xF3 un error inesperado.");
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: `\u274C Error: ${error instanceof Error ? error.message : "Ocurri\xF3 un error inesperado."}`
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, import_react4.useCallback)(
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, import_react4.useCallback)((question) => {
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, import_jsx_runtime5.jsxs)("div", { style: styles.metadataSection, children: [
3193
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles.metadataTitle, children: [
3194
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LayersIcon, {}),
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, import_jsx_runtime5.jsx)("ul", { style: styles.metadataList, children: referencedLayers.map((layer, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { style: styles.metadataItem, children: [
3198
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: layer.layerName }),
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, import_react4.useCallback)((action) => {
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, import_jsx_runtime5.jsxs)("div", { style: styles.actionsSection, children: [
3217
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.sectionLabel, children: "Acciones Sugeridas" }),
3218
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.actionsGrid, children: response.suggestedActions.map((action, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsxs)("div", { style: styles.actionsSection, children: [
3250
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.sectionLabel, children: "Preguntas Relacionadas" }),
3251
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: response.followUpQuestions.map((question, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsxs)("div", { style: styles.root, children: [
3281
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `
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
- inset: 0 !important;
3325
- width: 100vw !important;
3326
- max-width: 100vw !important;
3327
- height: 100vh !important;
3328
- height: 100dvh !important;
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, import_jsx_runtime5.jsxs)(
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, import_jsx_runtime5.jsxs)("header", { style: styles.header, children: [
3362
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { style: styles.title, children: "Asistente Zenit AI" }),
3363
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles.headerButtons, children: [
3364
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsx)(CollapseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpandIcon, {})
3589
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CollapseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ExpandIcon, {})
3378
3590
  }
3379
3591
  ),
3380
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsx)(CloseIcon, {})
3605
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {})
3394
3606
  }
3395
3607
  )
3396
3608
  ] })
3397
3609
  ] }),
3398
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: messagesContainerRef, className: "zenit-ai-body", style: styles.messages, children: [
3399
- messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsxs)(
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, import_jsx_runtime5.jsx)(MarkdownRenderer, { content: message.content }) : message.content,
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, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
3439
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MarkdownRenderer, { content: streamingText }),
3440
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: styles.cursor })
3441
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles.thinkingText, children: [
3442
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Analizando" }),
3443
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles.typingIndicator, children: [
3444
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
3445
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
3446
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot })
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, import_jsx_runtime5.jsx)("div", { ref: messagesEndRef })
3665
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: messagesEndRef })
3454
3666
  ] }),
3455
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "zenit-ai-input-area", style: styles.inputWrapper, children: [
3456
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsx)(SendIcon, {})
3694
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SendIcon, {})
3483
3695
  }
3484
3696
  )
3485
3697
  ] }),
3486
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.errorText, children: errorMessage }),
3487
- !mapId && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.statusNote, children: "Selecciona un mapa para usar el asistente" }),
3488
- !baseUrl && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.statusNote, children: "Configura la baseUrl del SDK" })
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, import_jsx_runtime5.jsx)(
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, import_jsx_runtime5.jsx)(CloseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
3504
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChatIcon, {}),
3505
- !isMobile && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Asistente IA" })
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, import_react_dom.createPortal)(chatContent, document.body);
3725
+ return (0, import_react_dom2.createPortal)(chatContent, document.body);
3512
3726
  }
3513
3727
  return chatContent;
3514
3728
  };