zenit-sdk 0.0.3 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-R73LRYVJ.mjs → chunk-ITF7QCUZ.mjs} +523 -72
- package/dist/chunk-ITF7QCUZ.mjs.map +1 -0
- package/dist/{index-Da0hFqDL.d.mts → index-kGwfqTc_.d.mts} +5 -0
- package/dist/{index-Da0hFqDL.d.ts → index-kGwfqTc_.d.ts} +5 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +523 -72
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/react/index.d.mts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +522 -71
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1 -1
- package/package.json +7 -27
- package/dist/chunk-R73LRYVJ.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/react/ZenitMap.tsx
|
|
2
|
-
import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, forwardRef } from "react";
|
|
2
|
+
import React, { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, forwardRef } from "react";
|
|
3
3
|
import { GeoJSON, MapContainer, Marker, TileLayer, ZoomControl, useMap } from "react-leaflet";
|
|
4
4
|
import L from "leaflet";
|
|
5
5
|
|
|
@@ -297,6 +297,366 @@ function getFeatureLayerId(feature) {
|
|
|
297
297
|
function escapeHtml(value) {
|
|
298
298
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
299
299
|
}
|
|
300
|
+
var DESCRIPTION_KEYS = /* @__PURE__ */ new Set(["descripcion", "description"]);
|
|
301
|
+
var POPUP_EXCLUDED_KEYS = /* @__PURE__ */ new Set(["geom", "geometry"]);
|
|
302
|
+
var POPUP_STYLE_ID = "zenit-leaflet-popup-styles";
|
|
303
|
+
var DESKTOP_POPUP_DIMENSIONS = { maxWidth: 350, minWidth: 280, maxHeight: 480 };
|
|
304
|
+
var MOBILE_POPUP_DIMENSIONS = { maxWidth: 280, minWidth: 240, maxHeight: 380 };
|
|
305
|
+
var ZENIT_LEAFLET_POPUP_STYLES = `
|
|
306
|
+
/* ===== Zenit Leaflet Popup - Modern Professional Styling ===== */
|
|
307
|
+
|
|
308
|
+
/* Main popup wrapper */
|
|
309
|
+
.zenit-leaflet-popup .leaflet-popup-content-wrapper {
|
|
310
|
+
border-radius: 12px;
|
|
311
|
+
box-shadow:
|
|
312
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
313
|
+
0 2px 4px -2px rgba(0, 0, 0, 0.1),
|
|
314
|
+
0 0 0 1px rgba(0, 0, 0, 0.05);
|
|
315
|
+
padding: 0;
|
|
316
|
+
background: #ffffff;
|
|
317
|
+
overflow: hidden;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/* Content area with scroll support */
|
|
321
|
+
.zenit-leaflet-popup .leaflet-popup-content {
|
|
322
|
+
margin: 0;
|
|
323
|
+
padding: 0;
|
|
324
|
+
font-size: 13px;
|
|
325
|
+
line-height: 1.5;
|
|
326
|
+
color: #374151;
|
|
327
|
+
min-width: 100%;
|
|
328
|
+
overflow-y: auto;
|
|
329
|
+
overflow-x: hidden;
|
|
330
|
+
scrollbar-width: thin;
|
|
331
|
+
scrollbar-color: rgba(156, 163, 175, 0.5) transparent;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/* Popup tip/arrow shadow */
|
|
335
|
+
.zenit-leaflet-popup .leaflet-popup-tip-container {
|
|
336
|
+
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.zenit-leaflet-popup .leaflet-popup-tip {
|
|
340
|
+
background: #ffffff;
|
|
341
|
+
box-shadow: none;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/* Close button styling */
|
|
345
|
+
.zenit-leaflet-popup .leaflet-popup-close-button {
|
|
346
|
+
color: #9ca3af;
|
|
347
|
+
font-size: 18px;
|
|
348
|
+
font-weight: 400;
|
|
349
|
+
width: 28px;
|
|
350
|
+
height: 28px;
|
|
351
|
+
padding: 0;
|
|
352
|
+
margin: 8px 8px 0 0;
|
|
353
|
+
display: flex;
|
|
354
|
+
align-items: center;
|
|
355
|
+
justify-content: center;
|
|
356
|
+
border-radius: 6px;
|
|
357
|
+
transition: all 0.15s ease;
|
|
358
|
+
z-index: 10;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.zenit-leaflet-popup .leaflet-popup-close-button:hover {
|
|
362
|
+
color: #374151;
|
|
363
|
+
background-color: #f3f4f6;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.zenit-leaflet-popup .leaflet-popup-close-button:active {
|
|
367
|
+
background-color: #e5e7eb;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/* Main card container */
|
|
371
|
+
.zenit-popup-card {
|
|
372
|
+
display: flex;
|
|
373
|
+
flex-direction: column;
|
|
374
|
+
gap: 0;
|
|
375
|
+
padding: 16px;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/* Individual row styling with subtle separator */
|
|
379
|
+
.zenit-popup-row {
|
|
380
|
+
display: flex;
|
|
381
|
+
flex-direction: column;
|
|
382
|
+
gap: 2px;
|
|
383
|
+
padding: 10px 0;
|
|
384
|
+
border-bottom: 1px solid #f3f4f6;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.zenit-popup-row:first-child {
|
|
388
|
+
padding-top: 0;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.zenit-popup-row:last-child {
|
|
392
|
+
border-bottom: none;
|
|
393
|
+
padding-bottom: 0;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/* Label styling - small, gray, uppercase */
|
|
397
|
+
.zenit-popup-label {
|
|
398
|
+
font-size: 10px;
|
|
399
|
+
font-weight: 500;
|
|
400
|
+
color: #9ca3af;
|
|
401
|
+
text-transform: uppercase;
|
|
402
|
+
letter-spacing: 0.05em;
|
|
403
|
+
line-height: 1.4;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/* Value styling - darker, readable */
|
|
407
|
+
.zenit-popup-value {
|
|
408
|
+
font-size: 13px;
|
|
409
|
+
font-weight: 400;
|
|
410
|
+
color: #1f2937;
|
|
411
|
+
overflow-wrap: break-word;
|
|
412
|
+
word-break: break-word;
|
|
413
|
+
line-height: 1.5;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* Special styling for description field */
|
|
417
|
+
.zenit-popup-row.zenit-popup-description {
|
|
418
|
+
background-color: #f9fafb;
|
|
419
|
+
margin: 0 -16px;
|
|
420
|
+
padding: 12px 16px;
|
|
421
|
+
border-bottom: 1px solid #e5e7eb;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.zenit-popup-row.zenit-popup-description:first-child {
|
|
425
|
+
margin-top: 0;
|
|
426
|
+
border-radius: 0;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.zenit-popup-row.zenit-popup-description .zenit-popup-value {
|
|
430
|
+
font-size: 13px;
|
|
431
|
+
line-height: 1.6;
|
|
432
|
+
color: #374151;
|
|
433
|
+
max-height: 150px;
|
|
434
|
+
overflow-y: auto;
|
|
435
|
+
padding-right: 4px;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/* Preformatted text (JSON objects) */
|
|
439
|
+
.zenit-popup-pre {
|
|
440
|
+
margin: 0;
|
|
441
|
+
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
442
|
+
font-size: 11px;
|
|
443
|
+
white-space: pre-wrap;
|
|
444
|
+
word-break: break-word;
|
|
445
|
+
color: #4b5563;
|
|
446
|
+
background-color: #f9fafb;
|
|
447
|
+
padding: 8px;
|
|
448
|
+
border-radius: 6px;
|
|
449
|
+
border: 1px solid #e5e7eb;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/* Empty state styling */
|
|
453
|
+
.zenit-popup-empty {
|
|
454
|
+
font-size: 13px;
|
|
455
|
+
color: #9ca3af;
|
|
456
|
+
font-style: italic;
|
|
457
|
+
text-align: center;
|
|
458
|
+
padding: 20px 0;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/* Webkit scrollbar styling */
|
|
462
|
+
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar {
|
|
463
|
+
width: 6px;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-track {
|
|
467
|
+
background: transparent;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb {
|
|
471
|
+
background-color: rgba(156, 163, 175, 0.4);
|
|
472
|
+
border-radius: 3px;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb:hover {
|
|
476
|
+
background-color: rgba(107, 114, 128, 0.6);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/* Scrollbar for description field */
|
|
480
|
+
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar {
|
|
481
|
+
width: 4px;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar-track {
|
|
485
|
+
background: transparent;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar-thumb {
|
|
489
|
+
background-color: rgba(156, 163, 175, 0.4);
|
|
490
|
+
border-radius: 2px;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/* ===== Responsive: Mobile (<640px) ===== */
|
|
494
|
+
@media (max-width: 640px) {
|
|
495
|
+
.zenit-leaflet-popup .leaflet-popup-content-wrapper {
|
|
496
|
+
border-radius: 10px;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.zenit-leaflet-popup .leaflet-popup-close-button {
|
|
500
|
+
width: 26px;
|
|
501
|
+
height: 26px;
|
|
502
|
+
font-size: 16px;
|
|
503
|
+
margin: 6px 6px 0 0;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.zenit-popup-card {
|
|
507
|
+
padding: 12px;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.zenit-popup-row {
|
|
511
|
+
padding: 8px 0;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.zenit-popup-label {
|
|
515
|
+
font-size: 9px;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.zenit-popup-value {
|
|
519
|
+
font-size: 12px;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.zenit-popup-row.zenit-popup-description {
|
|
523
|
+
margin: 0 -12px;
|
|
524
|
+
padding: 10px 12px;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
.zenit-popup-row.zenit-popup-description .zenit-popup-value {
|
|
528
|
+
font-size: 12px;
|
|
529
|
+
max-height: 120px;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
.zenit-popup-pre {
|
|
533
|
+
font-size: 10px;
|
|
534
|
+
padding: 6px;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
.zenit-popup-empty {
|
|
538
|
+
font-size: 12px;
|
|
539
|
+
padding: 16px 0;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/* ===== Map tooltip styling ===== */
|
|
544
|
+
.zenit-map-tooltip {
|
|
545
|
+
background-color: rgba(31, 41, 55, 0.95);
|
|
546
|
+
border: none;
|
|
547
|
+
border-radius: 6px;
|
|
548
|
+
color: #ffffff;
|
|
549
|
+
font-size: 12px;
|
|
550
|
+
font-weight: 500;
|
|
551
|
+
padding: 6px 10px;
|
|
552
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.zenit-map-tooltip::before {
|
|
556
|
+
border-top-color: rgba(31, 41, 55, 0.95);
|
|
557
|
+
}
|
|
558
|
+
`;
|
|
559
|
+
function ensurePopupStyles() {
|
|
560
|
+
if (typeof document === "undefined") return;
|
|
561
|
+
if (document.getElementById(POPUP_STYLE_ID)) return;
|
|
562
|
+
const styleTag = document.createElement("style");
|
|
563
|
+
styleTag.id = POPUP_STYLE_ID;
|
|
564
|
+
styleTag.textContent = ZENIT_LEAFLET_POPUP_STYLES;
|
|
565
|
+
document.head.appendChild(styleTag);
|
|
566
|
+
}
|
|
567
|
+
function getPopupDimensions() {
|
|
568
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
569
|
+
return DESKTOP_POPUP_DIMENSIONS;
|
|
570
|
+
}
|
|
571
|
+
return window.matchMedia("(max-width: 640px)").matches ? MOBILE_POPUP_DIMENSIONS : DESKTOP_POPUP_DIMENSIONS;
|
|
572
|
+
}
|
|
573
|
+
function normalizeDescriptionValue(value) {
|
|
574
|
+
if (value === void 0 || value === null) return null;
|
|
575
|
+
if (typeof value === "string") {
|
|
576
|
+
const trimmed = value.trim();
|
|
577
|
+
return trimmed ? trimmed : null;
|
|
578
|
+
}
|
|
579
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
580
|
+
return String(value);
|
|
581
|
+
}
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
584
|
+
function extractDescriptionValue(properties) {
|
|
585
|
+
if (!properties) return null;
|
|
586
|
+
const matches = Object.entries(properties).find(
|
|
587
|
+
([key]) => DESCRIPTION_KEYS.has(key.toLowerCase())
|
|
588
|
+
);
|
|
589
|
+
if (!matches) return null;
|
|
590
|
+
return normalizeDescriptionValue(matches[1]);
|
|
591
|
+
}
|
|
592
|
+
function safeJsonStringify(value) {
|
|
593
|
+
try {
|
|
594
|
+
const json = JSON.stringify(value, null, 2);
|
|
595
|
+
if (json !== void 0) return json;
|
|
596
|
+
} catch {
|
|
597
|
+
}
|
|
598
|
+
return String(value);
|
|
599
|
+
}
|
|
600
|
+
function renderPopupValue(value) {
|
|
601
|
+
if (value === null || value === void 0) {
|
|
602
|
+
return '<span class="zenit-popup-empty">Sin datos</span>';
|
|
603
|
+
}
|
|
604
|
+
if (typeof value === "object") {
|
|
605
|
+
const json = safeJsonStringify(value);
|
|
606
|
+
return `<pre class="zenit-popup-pre">${escapeHtml(json)}</pre>`;
|
|
607
|
+
}
|
|
608
|
+
return `<span>${escapeHtml(String(value))}</span>`;
|
|
609
|
+
}
|
|
610
|
+
function shouldIncludePopupEntry(key, value) {
|
|
611
|
+
if (!key) return false;
|
|
612
|
+
const normalized = key.trim().toLowerCase();
|
|
613
|
+
if (!normalized) return false;
|
|
614
|
+
if (normalized.startsWith("_")) return false;
|
|
615
|
+
if (POPUP_EXCLUDED_KEYS.has(normalized)) return false;
|
|
616
|
+
if (value === null || value === void 0) return false;
|
|
617
|
+
if (typeof value === "string" && !value.trim()) return false;
|
|
618
|
+
return true;
|
|
619
|
+
}
|
|
620
|
+
function isDescriptionKey(key) {
|
|
621
|
+
const normalized = key.trim().toLowerCase();
|
|
622
|
+
return DESCRIPTION_KEYS.has(normalized);
|
|
623
|
+
}
|
|
624
|
+
function formatLabel(key) {
|
|
625
|
+
return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").trim();
|
|
626
|
+
}
|
|
627
|
+
function createPopupContent(properties) {
|
|
628
|
+
const entries = Object.entries(properties).filter(
|
|
629
|
+
([key, value]) => shouldIncludePopupEntry(key, value)
|
|
630
|
+
);
|
|
631
|
+
if (entries.length === 0) {
|
|
632
|
+
return `<div class="zenit-popup-card"><div class="zenit-popup-empty">Sin datos disponibles</div></div>`;
|
|
633
|
+
}
|
|
634
|
+
const descriptionEntry = entries.find(([key]) => isDescriptionKey(key));
|
|
635
|
+
const otherEntries = entries.filter(([key]) => !isDescriptionKey(key));
|
|
636
|
+
let rowsHtml = "";
|
|
637
|
+
if (descriptionEntry) {
|
|
638
|
+
const [key, value] = descriptionEntry;
|
|
639
|
+
const label = escapeHtml(formatLabel(key));
|
|
640
|
+
const valueHtml = renderPopupValue(value);
|
|
641
|
+
rowsHtml += `
|
|
642
|
+
<div class="zenit-popup-row zenit-popup-description">
|
|
643
|
+
<div class="zenit-popup-label">${label}</div>
|
|
644
|
+
<div class="zenit-popup-value">${valueHtml}</div>
|
|
645
|
+
</div>
|
|
646
|
+
`;
|
|
647
|
+
}
|
|
648
|
+
rowsHtml += otherEntries.map(([key, value]) => {
|
|
649
|
+
const label = escapeHtml(formatLabel(key));
|
|
650
|
+
const valueHtml = renderPopupValue(value);
|
|
651
|
+
return `
|
|
652
|
+
<div class="zenit-popup-row">
|
|
653
|
+
<div class="zenit-popup-label">${label}</div>
|
|
654
|
+
<div class="zenit-popup-value">${valueHtml}</div>
|
|
655
|
+
</div>
|
|
656
|
+
`;
|
|
657
|
+
}).join("");
|
|
658
|
+
return `<div class="zenit-popup-card">${rowsHtml}</div>`;
|
|
659
|
+
}
|
|
300
660
|
function withAlpha(color, alpha) {
|
|
301
661
|
const trimmed = color.trim();
|
|
302
662
|
if (trimmed.startsWith("#")) {
|
|
@@ -365,40 +725,39 @@ function getFeatureStyleOverrides(feature) {
|
|
|
365
725
|
function buildFeaturePopupHtml(feature) {
|
|
366
726
|
const properties = feature?.properties;
|
|
367
727
|
if (!properties) return null;
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
if (
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
const val = escapeHtml(String(value));
|
|
397
|
-
return `<div><strong>${label}:</strong> ${val}</div>`;
|
|
398
|
-
}).join("");
|
|
399
|
-
parts.push(`<div style="font-size:12px;line-height:1.4;">${rows}</div>`);
|
|
728
|
+
const rendered = createPopupContent(properties);
|
|
729
|
+
return rendered ? rendered : null;
|
|
730
|
+
}
|
|
731
|
+
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
732
|
+
function getGeometryType(feature) {
|
|
733
|
+
const t = feature?.geometry?.type;
|
|
734
|
+
return typeof t === "string" ? t : null;
|
|
735
|
+
}
|
|
736
|
+
function isPointGeometry(feature) {
|
|
737
|
+
const geometryType = getGeometryType(feature);
|
|
738
|
+
return geometryType !== null && POINT_GEOMETRY_TYPES.has(geometryType);
|
|
739
|
+
}
|
|
740
|
+
function isNonPointGeometry(feature) {
|
|
741
|
+
const geometryType = getGeometryType(feature);
|
|
742
|
+
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
743
|
+
}
|
|
744
|
+
function buildFeatureCollection(features) {
|
|
745
|
+
return {
|
|
746
|
+
type: "FeatureCollection",
|
|
747
|
+
features
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
function pickIntersectFeature(baseFeature, candidates) {
|
|
751
|
+
if (!Array.isArray(candidates) || candidates.length === 0) return null;
|
|
752
|
+
const baseId = baseFeature?.id;
|
|
753
|
+
if (baseId !== void 0 && baseId !== null) {
|
|
754
|
+
const matchById = candidates.find((candidate) => candidate?.id === baseId);
|
|
755
|
+
if (matchById) return matchById;
|
|
400
756
|
}
|
|
401
|
-
|
|
757
|
+
const matchWithDescription = candidates.find(
|
|
758
|
+
(candidate) => extractDescriptionValue(candidate?.properties)
|
|
759
|
+
);
|
|
760
|
+
return matchWithDescription ?? candidates[0];
|
|
402
761
|
}
|
|
403
762
|
function normalizeCenterTuple(center) {
|
|
404
763
|
if (!center) return null;
|
|
@@ -519,6 +878,7 @@ var ZenitMap = forwardRef(({
|
|
|
519
878
|
const [loadingMap, setLoadingMap] = useState(false);
|
|
520
879
|
const [mapError, setMapError] = useState(null);
|
|
521
880
|
const [mapInstance, setMapInstance] = useState(null);
|
|
881
|
+
const [panesReady, setPanesReady] = useState(false);
|
|
522
882
|
const [currentZoom, setCurrentZoom] = useState(initialZoom ?? DEFAULT_ZOOM);
|
|
523
883
|
const [isMobile, setIsMobile] = useState(() => {
|
|
524
884
|
if (typeof window === "undefined") return false;
|
|
@@ -543,6 +903,11 @@ var ZenitMap = forwardRef(({
|
|
|
543
903
|
}
|
|
544
904
|
return;
|
|
545
905
|
}, []);
|
|
906
|
+
useEffect(() => {
|
|
907
|
+
if (featureInfoMode === "popup") {
|
|
908
|
+
ensurePopupStyles();
|
|
909
|
+
}
|
|
910
|
+
}, [featureInfoMode]);
|
|
546
911
|
const layerStyleIndex = useMemo(() => {
|
|
547
912
|
const index = /* @__PURE__ */ new Map();
|
|
548
913
|
(map?.mapLayers ?? []).forEach((entry) => {
|
|
@@ -833,16 +1198,23 @@ var ZenitMap = forwardRef(({
|
|
|
833
1198
|
(targetMap, targetLayers) => {
|
|
834
1199
|
const baseZIndex = 400;
|
|
835
1200
|
targetLayers.forEach((layer) => {
|
|
836
|
-
const paneName = `zenit-layer-${layer.layerId}`;
|
|
837
|
-
const pane = targetMap.getPane(paneName) ?? targetMap.createPane(paneName);
|
|
838
1201
|
const order = Number.isFinite(layer.displayOrder) ? layer.displayOrder : 0;
|
|
839
|
-
|
|
1202
|
+
const fillPaneName = `zenit-layer-${layer.layerId}-fill`;
|
|
1203
|
+
const pointPaneName = `zenit-layer-${layer.layerId}-points`;
|
|
1204
|
+
const labelPaneName = `zenit-layer-${layer.layerId}-labels`;
|
|
1205
|
+
const fillPane = targetMap.getPane(fillPaneName) ?? targetMap.createPane(fillPaneName);
|
|
1206
|
+
const pointPane = targetMap.getPane(pointPaneName) ?? targetMap.createPane(pointPaneName);
|
|
1207
|
+
const labelPane = targetMap.getPane(labelPaneName) ?? targetMap.createPane(labelPaneName);
|
|
1208
|
+
fillPane.style.zIndex = String(baseZIndex + order);
|
|
1209
|
+
pointPane.style.zIndex = String(baseZIndex + order + 1e3);
|
|
1210
|
+
labelPane.style.zIndex = String(baseZIndex + order + 2e3);
|
|
840
1211
|
});
|
|
841
1212
|
},
|
|
842
1213
|
[]
|
|
843
1214
|
);
|
|
844
1215
|
const handleMapReady = useCallback(
|
|
845
1216
|
(instance) => {
|
|
1217
|
+
setPanesReady(false);
|
|
846
1218
|
setMapInstance(instance);
|
|
847
1219
|
onMapReady?.(instance);
|
|
848
1220
|
},
|
|
@@ -850,6 +1222,7 @@ var ZenitMap = forwardRef(({
|
|
|
850
1222
|
);
|
|
851
1223
|
useEffect(() => {
|
|
852
1224
|
if (!mapInstance) {
|
|
1225
|
+
setPanesReady(false);
|
|
853
1226
|
return;
|
|
854
1227
|
}
|
|
855
1228
|
if (orderedLayers.length === 0) {
|
|
@@ -860,6 +1233,11 @@ var ZenitMap = forwardRef(({
|
|
|
860
1233
|
displayOrder: layer.displayOrder
|
|
861
1234
|
}));
|
|
862
1235
|
ensureLayerPanes(mapInstance, layerTargets);
|
|
1236
|
+
const first = layerTargets[0];
|
|
1237
|
+
const testPane = mapInstance.getPane(`zenit-layer-${first.layerId}-labels`);
|
|
1238
|
+
if (testPane) {
|
|
1239
|
+
setPanesReady(true);
|
|
1240
|
+
}
|
|
863
1241
|
}, [mapInstance, orderedLayers, ensureLayerPanes]);
|
|
864
1242
|
const overlayOnEachFeature = useMemo(() => {
|
|
865
1243
|
return (feature, layer) => {
|
|
@@ -877,7 +1255,17 @@ var ZenitMap = forwardRef(({
|
|
|
877
1255
|
if (featureInfoMode === "popup") {
|
|
878
1256
|
const content = buildFeaturePopupHtml(feature);
|
|
879
1257
|
if (content) {
|
|
880
|
-
|
|
1258
|
+
const { maxWidth, minWidth, maxHeight } = getPopupDimensions();
|
|
1259
|
+
layer.bindPopup(content, {
|
|
1260
|
+
maxWidth,
|
|
1261
|
+
minWidth,
|
|
1262
|
+
maxHeight,
|
|
1263
|
+
className: "zenit-leaflet-popup",
|
|
1264
|
+
autoPan: true,
|
|
1265
|
+
closeButton: true,
|
|
1266
|
+
keepInView: true,
|
|
1267
|
+
offset: L.point(0, -24)
|
|
1268
|
+
});
|
|
881
1269
|
}
|
|
882
1270
|
}
|
|
883
1271
|
if (isPointFeature && layer.bindTooltip) {
|
|
@@ -888,7 +1276,37 @@ var ZenitMap = forwardRef(({
|
|
|
888
1276
|
className: "zenit-map-tooltip"
|
|
889
1277
|
});
|
|
890
1278
|
}
|
|
891
|
-
layer.on("click", () =>
|
|
1279
|
+
layer.on("click", () => {
|
|
1280
|
+
if (featureInfoMode === "popup" && client && layerId !== void 0 && !extractDescriptionValue(feature?.properties) && feature?.geometry) {
|
|
1281
|
+
const trackedFeature = feature;
|
|
1282
|
+
if (!trackedFeature.__zenit_popup_loaded) {
|
|
1283
|
+
trackedFeature.__zenit_popup_loaded = true;
|
|
1284
|
+
client.layers.getLayerGeoJsonIntersect({
|
|
1285
|
+
id: layerId,
|
|
1286
|
+
geometry: feature.geometry
|
|
1287
|
+
}).then((response) => {
|
|
1288
|
+
const candidates = response.data?.features ?? [];
|
|
1289
|
+
const resolved = pickIntersectFeature(feature, candidates);
|
|
1290
|
+
if (!resolved?.properties) return;
|
|
1291
|
+
const mergedProperties = {
|
|
1292
|
+
...trackedFeature.properties ?? {},
|
|
1293
|
+
...resolved.properties
|
|
1294
|
+
};
|
|
1295
|
+
trackedFeature.properties = mergedProperties;
|
|
1296
|
+
const updatedHtml = buildFeaturePopupHtml({
|
|
1297
|
+
...feature,
|
|
1298
|
+
properties: mergedProperties
|
|
1299
|
+
});
|
|
1300
|
+
if (updatedHtml && layer.setPopupContent) {
|
|
1301
|
+
layer.setPopupContent(updatedHtml);
|
|
1302
|
+
}
|
|
1303
|
+
}).catch(() => {
|
|
1304
|
+
trackedFeature.__zenit_popup_loaded = false;
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
onFeatureClick?.(feature, layerId);
|
|
1309
|
+
});
|
|
892
1310
|
layer.on("mouseover", () => {
|
|
893
1311
|
if (layer instanceof L.Path && originalStyle) {
|
|
894
1312
|
layer.setStyle({
|
|
@@ -912,7 +1330,7 @@ var ZenitMap = forwardRef(({
|
|
|
912
1330
|
}
|
|
913
1331
|
});
|
|
914
1332
|
};
|
|
915
|
-
}, [featureInfoMode, onFeatureClick, onFeatureHover]);
|
|
1333
|
+
}, [client, featureInfoMode, onFeatureClick, onFeatureHover]);
|
|
916
1334
|
const buildLayerStyle = (layerId, baseOpacity, feature, layerType) => {
|
|
917
1335
|
const style = resolveLayerStyle(layerId);
|
|
918
1336
|
const featureStyleOverrides = getFeatureStyleOverrides(feature);
|
|
@@ -1093,22 +1511,50 @@ var ZenitMap = forwardRef(({
|
|
|
1093
1511
|
/* @__PURE__ */ jsx(ZoomBasedOpacityHandler, { onZoomChange: handleZoomChange }),
|
|
1094
1512
|
orderedLayers.map((layerState) => {
|
|
1095
1513
|
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
1096
|
-
const
|
|
1514
|
+
const fillPaneName = `zenit-layer-${layerState.mapLayer.layerId}-fill`;
|
|
1515
|
+
const pointsPaneName = `zenit-layer-${layerState.mapLayer.layerId}-points`;
|
|
1516
|
+
const labelPaneName = `zenit-layer-${layerState.mapLayer.layerId}-labels`;
|
|
1097
1517
|
const layerType = layerState.layer?.layerType ?? layerState.mapLayer.layerType ?? void 0;
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1518
|
+
const data = layerState.data?.features ?? [];
|
|
1519
|
+
const fillFeatures = data.filter(isNonPointGeometry);
|
|
1520
|
+
const pointFeatures = data.filter(isPointGeometry);
|
|
1521
|
+
const fillData = fillFeatures.length > 0 ? buildFeatureCollection(fillFeatures) : null;
|
|
1522
|
+
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
1523
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
1524
|
+
fillData && /* @__PURE__ */ jsx(
|
|
1525
|
+
GeoJSON,
|
|
1526
|
+
{
|
|
1527
|
+
data: fillData,
|
|
1528
|
+
pane: panesReady && mapInstance?.getPane(fillPaneName) ? fillPaneName : void 0,
|
|
1529
|
+
style: (feature) => buildLayerStyle(layerState.mapLayer.layerId, baseOpacity, feature, layerType),
|
|
1530
|
+
onEachFeature: overlayOnEachFeature
|
|
1531
|
+
}
|
|
1532
|
+
),
|
|
1533
|
+
pointsData && /* @__PURE__ */ jsx(
|
|
1534
|
+
GeoJSON,
|
|
1535
|
+
{
|
|
1536
|
+
data: pointsData,
|
|
1537
|
+
pane: panesReady && mapInstance?.getPane(pointsPaneName) ? pointsPaneName : void 0,
|
|
1538
|
+
pointToLayer: (feature, latlng) => L.circleMarker(latlng, {
|
|
1539
|
+
radius: isMobile ? 8 : 6,
|
|
1540
|
+
...buildLayerStyle(layerState.mapLayer.layerId, baseOpacity, feature, layerType)
|
|
1541
|
+
}),
|
|
1542
|
+
onEachFeature: overlayOnEachFeature
|
|
1543
|
+
}
|
|
1544
|
+
),
|
|
1545
|
+
panesReady && mapInstance?.getPane(labelPaneName) ? labelMarkers.filter(
|
|
1546
|
+
(marker) => String(marker.layerId) === String(layerState.mapLayer.layerId)
|
|
1547
|
+
).map((marker) => /* @__PURE__ */ jsx(
|
|
1548
|
+
Marker,
|
|
1549
|
+
{
|
|
1550
|
+
position: marker.position,
|
|
1551
|
+
icon: buildLabelIcon(marker.label, marker.opacity, marker.color),
|
|
1552
|
+
interactive: false,
|
|
1553
|
+
pane: labelPaneName
|
|
1554
|
+
},
|
|
1555
|
+
marker.key
|
|
1556
|
+
)) : null
|
|
1557
|
+
] }, layerState.mapLayer.layerId.toString());
|
|
1112
1558
|
}),
|
|
1113
1559
|
overlayGeojson && /* @__PURE__ */ jsx(
|
|
1114
1560
|
GeoJSON,
|
|
@@ -1118,16 +1564,7 @@ var ZenitMap = forwardRef(({
|
|
|
1118
1564
|
onEachFeature: overlayOnEachFeature
|
|
1119
1565
|
},
|
|
1120
1566
|
"zenit-overlay-geojson"
|
|
1121
|
-
)
|
|
1122
|
-
labelMarkers.map((marker) => /* @__PURE__ */ jsx(
|
|
1123
|
-
Marker,
|
|
1124
|
-
{
|
|
1125
|
-
position: marker.position,
|
|
1126
|
-
icon: buildLabelIcon(marker.label, marker.opacity, marker.color),
|
|
1127
|
-
interactive: false
|
|
1128
|
-
},
|
|
1129
|
-
marker.key
|
|
1130
|
-
))
|
|
1567
|
+
)
|
|
1131
1568
|
]
|
|
1132
1569
|
},
|
|
1133
1570
|
String(mapId)
|
|
@@ -2543,9 +2980,19 @@ var FloatingChatBox = ({
|
|
|
2543
2980
|
getAccessToken,
|
|
2544
2981
|
onActionClick,
|
|
2545
2982
|
onOpenChange,
|
|
2546
|
-
hideButton
|
|
2983
|
+
hideButton,
|
|
2984
|
+
open: openProp
|
|
2547
2985
|
}) => {
|
|
2548
|
-
const
|
|
2986
|
+
const isControlled = openProp !== void 0;
|
|
2987
|
+
const [internalOpen, setInternalOpen] = useState4(false);
|
|
2988
|
+
const open = isControlled ? openProp : internalOpen;
|
|
2989
|
+
const setOpen = useCallback3((value) => {
|
|
2990
|
+
const newValue = typeof value === "function" ? value(open) : value;
|
|
2991
|
+
if (!isControlled) {
|
|
2992
|
+
setInternalOpen(newValue);
|
|
2993
|
+
}
|
|
2994
|
+
onOpenChange?.(newValue);
|
|
2995
|
+
}, [isControlled, open, onOpenChange]);
|
|
2549
2996
|
const [expanded, setExpanded] = useState4(false);
|
|
2550
2997
|
const [messages, setMessages] = useState4([]);
|
|
2551
2998
|
const [inputValue, setInputValue] = useState4("");
|
|
@@ -2562,9 +3009,6 @@ var FloatingChatBox = ({
|
|
|
2562
3009
|
}, [accessToken, baseUrl, getAccessToken]);
|
|
2563
3010
|
const { sendMessage: sendMessage2, isStreaming, streamingText, completeResponse } = useSendMessageStream(chatConfig);
|
|
2564
3011
|
const canSend = Boolean(mapId) && Boolean(baseUrl) && inputValue.trim().length > 0 && !isStreaming;
|
|
2565
|
-
useEffect3(() => {
|
|
2566
|
-
onOpenChange?.(open);
|
|
2567
|
-
}, [open, onOpenChange]);
|
|
2568
3012
|
useEffect3(() => {
|
|
2569
3013
|
if (open && isMobile) {
|
|
2570
3014
|
setExpanded(true);
|
|
@@ -2717,6 +3161,13 @@ var FloatingChatBox = ({
|
|
|
2717
3161
|
] }, index)) })
|
|
2718
3162
|
] });
|
|
2719
3163
|
};
|
|
3164
|
+
const handleActionClick = useCallback3((action) => {
|
|
3165
|
+
if (isStreaming) return;
|
|
3166
|
+
setOpen(false);
|
|
3167
|
+
requestAnimationFrame(() => {
|
|
3168
|
+
onActionClick?.(action);
|
|
3169
|
+
});
|
|
3170
|
+
}, [isStreaming, setOpen, onActionClick]);
|
|
2720
3171
|
const renderActions = (response) => {
|
|
2721
3172
|
if (!response?.suggestedActions?.length) return null;
|
|
2722
3173
|
return /* @__PURE__ */ jsxs4("div", { style: styles.actionsSection, children: [
|
|
@@ -2730,7 +3181,7 @@ var FloatingChatBox = ({
|
|
|
2730
3181
|
opacity: isStreaming ? 0.5 : 1,
|
|
2731
3182
|
cursor: isStreaming ? "not-allowed" : "pointer"
|
|
2732
3183
|
},
|
|
2733
|
-
onClick: () =>
|
|
3184
|
+
onClick: () => handleActionClick(action),
|
|
2734
3185
|
disabled: isStreaming,
|
|
2735
3186
|
onMouseEnter: (e) => {
|
|
2736
3187
|
if (!isStreaming) {
|
|
@@ -3057,4 +3508,4 @@ export {
|
|
|
3057
3508
|
useSendMessageStream,
|
|
3058
3509
|
FloatingChatBox
|
|
3059
3510
|
};
|
|
3060
|
-
//# sourceMappingURL=chunk-
|
|
3511
|
+
//# sourceMappingURL=chunk-ITF7QCUZ.mjs.map
|