zenit-sdk 0.0.8 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/{chunk-52CLFD4L.mjs → chunk-PCTRVN4O.mjs} +1075 -1004
- package/dist/chunk-PCTRVN4O.mjs.map +1 -0
- package/dist/{index-kGwfqTc_.d.mts → index-DvcYGhqj.d.mts} +70 -4
- package/dist/{index-kGwfqTc_.d.ts → index-DvcYGhqj.d.ts} +70 -4
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1218 -1026
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +119 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +1077 -1006
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1 -1
- package/package.json +10 -7
- package/dist/chunk-52CLFD4L.mjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/react/ZenitMap.tsx
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
2
|
+
import React3, { useCallback as useCallback2, useEffect as useEffect4, useImperativeHandle, useMemo as useMemo2, useState as useState2, forwardRef } from "react";
|
|
3
|
+
import { MapContainer, Marker as Marker2, TileLayer, ZoomControl } from "react-leaflet";
|
|
4
|
+
import L4 from "leaflet";
|
|
5
5
|
|
|
6
6
|
// src/maps/helpers.ts
|
|
7
7
|
function toNumber(value) {
|
|
@@ -206,9 +206,9 @@ function getAccentByLayerId(layerId, mapLayers) {
|
|
|
206
206
|
|
|
207
207
|
// src/react/zoomOpacity.ts
|
|
208
208
|
var DEFAULT_OPTIONS = {
|
|
209
|
-
minZoom:
|
|
210
|
-
maxZoom:
|
|
211
|
-
minFactor: 0.
|
|
209
|
+
minZoom: 11,
|
|
210
|
+
maxZoom: 15,
|
|
211
|
+
minFactor: 0.3,
|
|
212
212
|
maxFactor: 1,
|
|
213
213
|
minOpacity: 0.1,
|
|
214
214
|
maxOpacity: 0.92
|
|
@@ -245,358 +245,215 @@ function getEffectiveLayerOpacity(baseOpacity, zoom, layerType, geometryType, op
|
|
|
245
245
|
return clampNumber(effective, settings.minOpacity, settings.maxOpacity);
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
// src/react/
|
|
249
|
-
import {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
var
|
|
253
|
-
function
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const coords = [];
|
|
257
|
-
const collect = (candidate) => {
|
|
258
|
-
if (!Array.isArray(candidate)) return;
|
|
259
|
-
if (candidate.length === 2 && typeof candidate[0] === "number" && typeof candidate[1] === "number") {
|
|
260
|
-
coords.push([candidate[0], candidate[1]]);
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
candidate.forEach((entry) => collect(entry));
|
|
264
|
-
};
|
|
265
|
-
geojson.features.forEach((feature) => {
|
|
266
|
-
collect(feature.geometry?.coordinates);
|
|
267
|
-
});
|
|
268
|
-
if (coords.length === 0) return null;
|
|
269
|
-
const [firstLon, firstLat] = coords[0];
|
|
270
|
-
const bbox = { minLon: firstLon, minLat: firstLat, maxLon: firstLon, maxLat: firstLat };
|
|
271
|
-
coords.forEach(([lon, lat]) => {
|
|
272
|
-
bbox.minLon = Math.min(bbox.minLon, lon);
|
|
273
|
-
bbox.minLat = Math.min(bbox.minLat, lat);
|
|
274
|
-
bbox.maxLon = Math.max(bbox.maxLon, lon);
|
|
275
|
-
bbox.maxLat = Math.max(bbox.maxLat, lat);
|
|
276
|
-
});
|
|
277
|
-
return bbox;
|
|
278
|
-
}
|
|
279
|
-
function mergeBBoxes(bboxes) {
|
|
280
|
-
const valid = bboxes.filter((bbox) => !!bbox);
|
|
281
|
-
if (valid.length === 0) return null;
|
|
282
|
-
const first = valid[0];
|
|
283
|
-
return valid.slice(1).reduce(
|
|
284
|
-
(acc, bbox) => ({
|
|
285
|
-
minLon: Math.min(acc.minLon, bbox.minLon),
|
|
286
|
-
minLat: Math.min(acc.minLat, bbox.minLat),
|
|
287
|
-
maxLon: Math.max(acc.maxLon, bbox.maxLon),
|
|
288
|
-
maxLat: Math.max(acc.maxLat, bbox.maxLat)
|
|
289
|
-
}),
|
|
290
|
-
{ ...first }
|
|
291
|
-
);
|
|
292
|
-
}
|
|
293
|
-
function isRecord(value) {
|
|
294
|
-
return typeof value === "object" && value !== null;
|
|
248
|
+
// src/react/map/layer-geojson.tsx
|
|
249
|
+
import { GeoJSON } from "react-leaflet";
|
|
250
|
+
import L from "leaflet";
|
|
251
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
252
|
+
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
253
|
+
function getGeometryType(feature) {
|
|
254
|
+
const t = feature?.geometry?.type;
|
|
255
|
+
return typeof t === "string" ? t : null;
|
|
295
256
|
}
|
|
296
|
-
function
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if (!Array.isArray(features)) return false;
|
|
300
|
-
const type = value.type;
|
|
301
|
-
return type === void 0 || type === "FeatureCollection";
|
|
257
|
+
function isPointGeometry(feature) {
|
|
258
|
+
const geometryType = getGeometryType(feature);
|
|
259
|
+
return geometryType !== null && POINT_GEOMETRY_TYPES.has(geometryType);
|
|
302
260
|
}
|
|
303
|
-
function
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
return isGeoJsonFeatureCollection(data) ? data : null;
|
|
307
|
-
}
|
|
308
|
-
return isGeoJsonFeatureCollection(value) ? value : null;
|
|
261
|
+
function isNonPointGeometry(feature) {
|
|
262
|
+
const geometryType = getGeometryType(feature);
|
|
263
|
+
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
309
264
|
}
|
|
310
|
-
function
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
265
|
+
function buildFeatureCollection(features) {
|
|
266
|
+
return {
|
|
267
|
+
type: "FeatureCollection",
|
|
268
|
+
features
|
|
269
|
+
};
|
|
314
270
|
}
|
|
315
|
-
|
|
316
|
-
|
|
271
|
+
var LayerGeoJson = ({
|
|
272
|
+
layerId,
|
|
273
|
+
data,
|
|
274
|
+
baseOpacity,
|
|
275
|
+
isMobile,
|
|
276
|
+
panesReady,
|
|
277
|
+
mapInstance,
|
|
278
|
+
fillPaneName,
|
|
279
|
+
pointsPaneName,
|
|
280
|
+
layerType,
|
|
281
|
+
styleFn,
|
|
282
|
+
onEachFeature,
|
|
283
|
+
onPolygonLabel
|
|
284
|
+
}) => {
|
|
285
|
+
const features = data.features ?? [];
|
|
286
|
+
const fillFeatures = features.filter(isNonPointGeometry);
|
|
287
|
+
const pointFeatures = features.filter(isPointGeometry);
|
|
288
|
+
const fillData = fillFeatures.length > 0 ? buildFeatureCollection(fillFeatures) : null;
|
|
289
|
+
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
290
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
291
|
+
fillData && /* @__PURE__ */ jsx(
|
|
292
|
+
GeoJSON,
|
|
293
|
+
{
|
|
294
|
+
data: fillData,
|
|
295
|
+
pane: panesReady && mapInstance?.getPane(fillPaneName) ? fillPaneName : void 0,
|
|
296
|
+
style: (feature) => styleFn(feature, layerType, baseOpacity),
|
|
297
|
+
onEachFeature: (feature, layer) => {
|
|
298
|
+
onEachFeature(feature, layer);
|
|
299
|
+
onPolygonLabel?.(feature, layer);
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
`fill-${layerId}`
|
|
303
|
+
),
|
|
304
|
+
pointsData && /* @__PURE__ */ jsx(
|
|
305
|
+
GeoJSON,
|
|
306
|
+
{
|
|
307
|
+
data: pointsData,
|
|
308
|
+
pane: panesReady && mapInstance?.getPane(pointsPaneName) ? pointsPaneName : void 0,
|
|
309
|
+
pointToLayer: (feature, latlng) => L.circleMarker(latlng, {
|
|
310
|
+
radius: isMobile ? 8 : 6,
|
|
311
|
+
...styleFn(feature, layerType, baseOpacity)
|
|
312
|
+
}),
|
|
313
|
+
onEachFeature
|
|
314
|
+
},
|
|
315
|
+
`points-${layerId}`
|
|
316
|
+
)
|
|
317
|
+
] });
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
// src/react/map/location-control.tsx
|
|
321
|
+
import { useEffect as useEffect2, useMemo, useRef as useRef2 } from "react";
|
|
322
|
+
import { createPortal } from "react-dom";
|
|
323
|
+
import { Circle, Marker, useMap } from "react-leaflet";
|
|
324
|
+
import L3 from "leaflet";
|
|
325
|
+
|
|
326
|
+
// src/react/hooks/use-geolocation.ts
|
|
327
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
328
|
+
function useGeolocation(options) {
|
|
329
|
+
const [isTracking, setIsTracking] = useState(false);
|
|
330
|
+
const [location, setLocation] = useState(null);
|
|
331
|
+
const [error, setError] = useState(null);
|
|
332
|
+
const watchIdRef = useRef(null);
|
|
333
|
+
const stopTracking = useCallback(() => {
|
|
334
|
+
if (watchIdRef.current !== null && typeof navigator !== "undefined" && navigator.geolocation) {
|
|
335
|
+
navigator.geolocation.clearWatch(watchIdRef.current);
|
|
336
|
+
}
|
|
337
|
+
watchIdRef.current = null;
|
|
338
|
+
setIsTracking(false);
|
|
339
|
+
}, []);
|
|
340
|
+
const startTracking = useCallback(() => {
|
|
341
|
+
if (typeof navigator === "undefined" || !navigator.geolocation) {
|
|
342
|
+
setError({ code: 0, message: "La geolocalizaci\xF3n no est\xE1 disponible en este navegador." });
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
setError(null);
|
|
346
|
+
watchIdRef.current = navigator.geolocation.watchPosition(
|
|
347
|
+
(position) => {
|
|
348
|
+
setLocation({
|
|
349
|
+
lat: position.coords.latitude,
|
|
350
|
+
lon: position.coords.longitude,
|
|
351
|
+
accuracy: position.coords.accuracy
|
|
352
|
+
});
|
|
353
|
+
setIsTracking(true);
|
|
354
|
+
},
|
|
355
|
+
(err) => {
|
|
356
|
+
setError({ code: err.code, message: err.message });
|
|
357
|
+
stopTracking();
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
enableHighAccuracy: options?.enableHighAccuracy ?? true,
|
|
361
|
+
timeout: options?.timeout ?? 12e3,
|
|
362
|
+
maximumAge: options?.maximumAge ?? 0
|
|
363
|
+
}
|
|
364
|
+
);
|
|
365
|
+
}, [options?.enableHighAccuracy, options?.maximumAge, options?.timeout, stopTracking]);
|
|
366
|
+
const toggleTracking = useCallback(() => {
|
|
367
|
+
if (isTracking) {
|
|
368
|
+
stopTracking();
|
|
369
|
+
} else {
|
|
370
|
+
startTracking();
|
|
371
|
+
}
|
|
372
|
+
}, [isTracking, startTracking, stopTracking]);
|
|
373
|
+
const clearError = useCallback(() => setError(null), []);
|
|
374
|
+
useEffect(() => {
|
|
375
|
+
return () => {
|
|
376
|
+
stopTracking();
|
|
377
|
+
};
|
|
378
|
+
}, [stopTracking]);
|
|
379
|
+
return {
|
|
380
|
+
isTracking,
|
|
381
|
+
location,
|
|
382
|
+
error,
|
|
383
|
+
startTracking,
|
|
384
|
+
stopTracking,
|
|
385
|
+
toggleTracking,
|
|
386
|
+
clearError
|
|
387
|
+
};
|
|
317
388
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
389
|
+
|
|
390
|
+
// src/react/map/map-utils.ts
|
|
391
|
+
import L2 from "leaflet";
|
|
321
392
|
var POPUP_STYLE_ID = "zenit-leaflet-popup-styles";
|
|
322
|
-
var
|
|
323
|
-
var
|
|
393
|
+
var POPUP_EXCLUDED_KEYS = /* @__PURE__ */ new Set(["geom", "geometry", "_private"]);
|
|
394
|
+
var POPUP_HEADER_KEYS = ["nombre", "name", "title", "titulo"];
|
|
395
|
+
var DESKTOP_POPUP_DIMENSIONS = { maxWidth: 360, minWidth: 280, maxHeight: 520 };
|
|
396
|
+
var MOBILE_POPUP_DIMENSIONS = { maxWidth: 300, minWidth: 240, maxHeight: 420 };
|
|
324
397
|
var ZENIT_LEAFLET_POPUP_STYLES = `
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
/* Main popup wrapper */
|
|
328
|
-
.zenit-leaflet-popup .leaflet-popup-content-wrapper {
|
|
398
|
+
.custom-leaflet-popup .leaflet-popup-content-wrapper {
|
|
329
399
|
border-radius: 12px;
|
|
330
|
-
box-shadow:
|
|
331
|
-
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
332
|
-
0 2px 4px -2px rgba(0, 0, 0, 0.1),
|
|
333
|
-
0 0 0 1px rgba(0, 0, 0, 0.05);
|
|
334
400
|
padding: 0;
|
|
335
401
|
background: #ffffff;
|
|
336
|
-
|
|
402
|
+
box-shadow: 0 12px 24px rgba(15, 23, 42, 0.18);
|
|
403
|
+
border: 1px solid rgba(15, 23, 42, 0.08);
|
|
337
404
|
}
|
|
338
405
|
|
|
339
|
-
|
|
340
|
-
.zenit-leaflet-popup .leaflet-popup-content {
|
|
406
|
+
.custom-leaflet-popup .leaflet-popup-content {
|
|
341
407
|
margin: 0;
|
|
342
|
-
padding:
|
|
408
|
+
padding: 12px 14px;
|
|
343
409
|
font-size: 13px;
|
|
344
|
-
line-height: 1.5;
|
|
345
|
-
color: #374151;
|
|
346
|
-
min-width: 100%;
|
|
347
|
-
max-height: min(70vh, 480px);
|
|
348
|
-
overflow-y: auto;
|
|
349
|
-
overflow-x: hidden;
|
|
350
|
-
scrollbar-width: thin;
|
|
351
|
-
scrollbar-color: rgba(156, 163, 175, 0.5) transparent;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/* Popup tip/arrow shadow */
|
|
355
|
-
.zenit-leaflet-popup .leaflet-popup-tip-container {
|
|
356
|
-
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
.zenit-leaflet-popup .leaflet-popup-tip {
|
|
360
|
-
background: #ffffff;
|
|
361
|
-
box-shadow: none;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/* Close button styling */
|
|
365
|
-
.zenit-leaflet-popup .leaflet-popup-close-button {
|
|
366
|
-
color: #9ca3af;
|
|
367
|
-
font-size: 18px;
|
|
368
|
-
font-weight: 400;
|
|
369
|
-
width: 28px;
|
|
370
|
-
height: 28px;
|
|
371
|
-
padding: 0;
|
|
372
|
-
margin: 8px 8px 0 0;
|
|
373
|
-
display: flex;
|
|
374
|
-
align-items: center;
|
|
375
|
-
justify-content: center;
|
|
376
|
-
border-radius: 6px;
|
|
377
|
-
transition: all 0.15s ease;
|
|
378
|
-
z-index: 10;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
.zenit-leaflet-popup .leaflet-popup-close-button:hover {
|
|
382
|
-
color: #374151;
|
|
383
|
-
background-color: #f3f4f6;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
.zenit-leaflet-popup .leaflet-popup-close-button:active {
|
|
387
|
-
background-color: #e5e7eb;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/* Main card container */
|
|
391
|
-
.zenit-popup-card {
|
|
392
|
-
display: flex;
|
|
393
|
-
flex-direction: column;
|
|
394
|
-
gap: 0;
|
|
395
|
-
padding: 16px;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
.zenit-popup-header {
|
|
399
|
-
padding-bottom: 12px;
|
|
400
|
-
border-bottom: 1px solid #e5e7eb;
|
|
401
|
-
margin-bottom: 4px;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
.zenit-popup-title {
|
|
405
|
-
font-size: 14px;
|
|
406
|
-
font-weight: 700;
|
|
407
|
-
color: #111827;
|
|
408
|
-
letter-spacing: 0.01em;
|
|
409
410
|
line-height: 1.4;
|
|
411
|
+
color: #0f172a;
|
|
412
|
+
max-height: min(70vh, 520px);
|
|
413
|
+
overflow: auto;
|
|
414
|
+
scrollbar-width: thin;
|
|
415
|
+
scrollbar-color: rgba(148, 163, 184, 0.6) transparent;
|
|
410
416
|
}
|
|
411
417
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
border-bottom: 1px solid #f3f4f6;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
.zenit-popup-row:first-child {
|
|
422
|
-
padding-top: 0;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
.zenit-popup-row:last-child {
|
|
426
|
-
border-bottom: none;
|
|
427
|
-
padding-bottom: 0;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/* Label styling - small, gray, uppercase */
|
|
431
|
-
.zenit-popup-label {
|
|
432
|
-
font-size: 10px;
|
|
433
|
-
font-weight: 500;
|
|
434
|
-
color: #9ca3af;
|
|
435
|
-
text-transform: uppercase;
|
|
436
|
-
letter-spacing: 0.05em;
|
|
437
|
-
line-height: 1.4;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
/* Value styling - darker, readable */
|
|
441
|
-
.zenit-popup-value {
|
|
442
|
-
font-size: 13px;
|
|
443
|
-
font-weight: 400;
|
|
444
|
-
color: #1f2937;
|
|
445
|
-
overflow-wrap: break-word;
|
|
446
|
-
word-break: break-word;
|
|
447
|
-
line-height: 1.5;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
.zenit-popup-link {
|
|
451
|
-
color: #2563eb;
|
|
452
|
-
text-decoration: underline;
|
|
453
|
-
font-weight: 500;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
.zenit-popup-link:hover {
|
|
457
|
-
color: #1d4ed8;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
/* Special styling for description field */
|
|
461
|
-
.zenit-popup-row.zenit-popup-description {
|
|
462
|
-
background-color: #f9fafb;
|
|
463
|
-
margin: 0 -16px;
|
|
464
|
-
padding: 12px 16px;
|
|
465
|
-
border-bottom: 1px solid #e5e7eb;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
.zenit-popup-row.zenit-popup-description:first-child {
|
|
469
|
-
margin-top: 0;
|
|
470
|
-
border-radius: 0;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value {
|
|
474
|
-
font-size: 13px;
|
|
475
|
-
line-height: 1.6;
|
|
476
|
-
color: #374151;
|
|
477
|
-
max-height: 150px;
|
|
478
|
-
overflow-y: auto;
|
|
479
|
-
padding-right: 4px;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
/* Preformatted text (JSON objects) */
|
|
483
|
-
.zenit-popup-pre {
|
|
484
|
-
margin: 0;
|
|
485
|
-
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
486
|
-
font-size: 11px;
|
|
487
|
-
white-space: pre-wrap;
|
|
488
|
-
word-break: break-word;
|
|
489
|
-
color: #4b5563;
|
|
490
|
-
background-color: #f9fafb;
|
|
491
|
-
padding: 8px;
|
|
492
|
-
border-radius: 6px;
|
|
493
|
-
border: 1px solid #e5e7eb;
|
|
418
|
+
.custom-leaflet-popup .leaflet-popup-close-button {
|
|
419
|
+
color: #64748b;
|
|
420
|
+
font-size: 16px;
|
|
421
|
+
padding: 6px 8px;
|
|
422
|
+
border-radius: 8px;
|
|
423
|
+
transition: background-color 0.15s ease, color 0.15s ease;
|
|
494
424
|
}
|
|
495
425
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
color: #9ca3af;
|
|
500
|
-
font-style: italic;
|
|
501
|
-
text-align: center;
|
|
502
|
-
padding: 20px 0;
|
|
426
|
+
.custom-leaflet-popup .leaflet-popup-close-button:hover {
|
|
427
|
+
color: #0f172a;
|
|
428
|
+
background: rgba(148, 163, 184, 0.2);
|
|
503
429
|
}
|
|
504
430
|
|
|
505
|
-
|
|
506
|
-
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar {
|
|
431
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar {
|
|
507
432
|
width: 6px;
|
|
508
433
|
}
|
|
509
434
|
|
|
510
|
-
.
|
|
511
|
-
background:
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
.zenit-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb {
|
|
515
|
-
background-color: rgba(156, 163, 175, 0.4);
|
|
516
|
-
border-radius: 3px;
|
|
435
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-thumb {
|
|
436
|
+
background: rgba(148, 163, 184, 0.5);
|
|
437
|
+
border-radius: 999px;
|
|
517
438
|
}
|
|
518
439
|
|
|
519
|
-
.
|
|
520
|
-
background-color: rgba(107, 114, 128, 0.6);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
/* Scrollbar for description field */
|
|
524
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar {
|
|
525
|
-
width: 4px;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar-track {
|
|
440
|
+
.custom-leaflet-popup .leaflet-popup-content::-webkit-scrollbar-track {
|
|
529
441
|
background: transparent;
|
|
530
442
|
}
|
|
531
443
|
|
|
532
|
-
.zenit-popup-row.zenit-popup-description .zenit-popup-value::-webkit-scrollbar-thumb {
|
|
533
|
-
background-color: rgba(156, 163, 175, 0.4);
|
|
534
|
-
border-radius: 2px;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
/* ===== Responsive: Mobile (<640px) ===== */
|
|
538
444
|
@media (max-width: 640px) {
|
|
539
|
-
.
|
|
540
|
-
border-radius: 10px;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
.zenit-leaflet-popup .leaflet-popup-close-button {
|
|
544
|
-
width: 26px;
|
|
545
|
-
height: 26px;
|
|
546
|
-
font-size: 16px;
|
|
547
|
-
margin: 6px 6px 0 0;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
.zenit-popup-card {
|
|
551
|
-
padding: 12px;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
.zenit-leaflet-popup .leaflet-popup-content {
|
|
555
|
-
max-height: min(65vh, 380px);
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
.zenit-popup-header {
|
|
559
|
-
padding-bottom: 10px;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
.zenit-popup-title {
|
|
563
|
-
font-size: 13px;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
.zenit-popup-row {
|
|
567
|
-
padding: 8px 0;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
.zenit-popup-label {
|
|
571
|
-
font-size: 9px;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
.zenit-popup-value {
|
|
445
|
+
.custom-leaflet-popup .leaflet-popup-content {
|
|
575
446
|
font-size: 12px;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
.zenit-popup-row.zenit-popup-description {
|
|
579
|
-
margin: 0 -12px;
|
|
580
447
|
padding: 10px 12px;
|
|
448
|
+
max-height: min(65vh, 420px);
|
|
581
449
|
}
|
|
582
450
|
|
|
583
|
-
.
|
|
584
|
-
font-size:
|
|
585
|
-
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
.zenit-popup-pre {
|
|
589
|
-
font-size: 10px;
|
|
590
|
-
padding: 6px;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
.zenit-popup-empty {
|
|
594
|
-
font-size: 12px;
|
|
595
|
-
padding: 16px 0;
|
|
451
|
+
.custom-leaflet-popup .leaflet-popup-close-button {
|
|
452
|
+
font-size: 14px;
|
|
453
|
+
padding: 4px 6px;
|
|
596
454
|
}
|
|
597
455
|
}
|
|
598
456
|
|
|
599
|
-
/* ===== Map tooltip styling ===== */
|
|
600
457
|
.zenit-map-tooltip {
|
|
601
458
|
background-color: rgba(31, 41, 55, 0.95);
|
|
602
459
|
border: none;
|
|
@@ -613,16 +470,21 @@ var ZENIT_LEAFLET_POPUP_STYLES = `
|
|
|
613
470
|
}
|
|
614
471
|
|
|
615
472
|
.polygon-label-tooltip {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
display: none !important;
|
|
473
|
+
background: rgba(15, 23, 42, 0.92);
|
|
474
|
+
border: none;
|
|
475
|
+
border-radius: 6px;
|
|
476
|
+
color: #f8fafc;
|
|
477
|
+
font-weight: 600;
|
|
478
|
+
font-size: 12px;
|
|
479
|
+
padding: 4px 8px;
|
|
624
480
|
}
|
|
625
481
|
`;
|
|
482
|
+
function clampNumber2(value, min, max) {
|
|
483
|
+
return Math.min(max, Math.max(min, value));
|
|
484
|
+
}
|
|
485
|
+
function clampOpacity4(value) {
|
|
486
|
+
return clampNumber2(value, 0, 1);
|
|
487
|
+
}
|
|
626
488
|
function ensurePopupStyles() {
|
|
627
489
|
if (typeof document === "undefined") return;
|
|
628
490
|
if (document.getElementById(POPUP_STYLE_ID)) return;
|
|
@@ -632,72 +494,52 @@ function ensurePopupStyles() {
|
|
|
632
494
|
document.head.appendChild(styleTag);
|
|
633
495
|
}
|
|
634
496
|
function getPopupDimensions() {
|
|
635
|
-
if (typeof window === "undefined"
|
|
497
|
+
if (typeof window === "undefined") {
|
|
636
498
|
return DESKTOP_POPUP_DIMENSIONS;
|
|
637
499
|
}
|
|
638
|
-
|
|
500
|
+
const isSmallWidth = window.innerWidth < 640;
|
|
501
|
+
const isShortHeight = window.innerHeight < 768;
|
|
502
|
+
const base = isSmallWidth ? MOBILE_POPUP_DIMENSIONS : DESKTOP_POPUP_DIMENSIONS;
|
|
503
|
+
const maxHeight = isShortHeight ? Math.min(base.maxHeight, 360) : base.maxHeight;
|
|
504
|
+
return { ...base, maxHeight };
|
|
639
505
|
}
|
|
640
|
-
function
|
|
641
|
-
|
|
642
|
-
if (typeof value === "string") {
|
|
643
|
-
const trimmed = value.trim();
|
|
644
|
-
return trimmed ? trimmed : null;
|
|
645
|
-
}
|
|
646
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
647
|
-
return String(value);
|
|
648
|
-
}
|
|
649
|
-
return null;
|
|
650
|
-
}
|
|
651
|
-
function extractDescriptionValue(properties) {
|
|
652
|
-
if (!properties) return null;
|
|
653
|
-
const matches = Object.entries(properties).find(
|
|
654
|
-
([key]) => DESCRIPTION_KEYS.has(key.toLowerCase())
|
|
655
|
-
);
|
|
656
|
-
if (!matches) return null;
|
|
657
|
-
return normalizeDescriptionValue(matches[1]);
|
|
506
|
+
function escapeHtml(value) {
|
|
507
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
658
508
|
}
|
|
659
|
-
function
|
|
660
|
-
|
|
661
|
-
const json = JSON.stringify(value, null, 2);
|
|
662
|
-
if (json !== void 0) return json;
|
|
663
|
-
} catch {
|
|
664
|
-
}
|
|
665
|
-
return String(value);
|
|
509
|
+
function formatLabel(key) {
|
|
510
|
+
return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").trim();
|
|
666
511
|
}
|
|
667
512
|
function renderPopupValue(value) {
|
|
668
|
-
if (value === null || value === void 0)
|
|
669
|
-
return '<span class="zenit-popup-empty">Sin datos</span>';
|
|
670
|
-
}
|
|
513
|
+
if (value === null || value === void 0) return '<span style="color:#94a3b8;">Sin datos</span>';
|
|
671
514
|
if (value instanceof Date) {
|
|
672
|
-
return
|
|
515
|
+
return escapeHtml(value.toLocaleDateString("es-GT"));
|
|
673
516
|
}
|
|
674
517
|
if (typeof value === "number") {
|
|
675
|
-
return
|
|
518
|
+
return escapeHtml(value.toLocaleString("es-GT"));
|
|
676
519
|
}
|
|
677
520
|
if (typeof value === "string") {
|
|
678
521
|
const trimmed = value.trim();
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
return `<span>${escapeHtml(new Date(parsed).toLocaleDateString("es-GT"))}</span>`;
|
|
684
|
-
}
|
|
685
|
-
}
|
|
522
|
+
if (!trimmed) return '<span style="color:#94a3b8;">Sin datos</span>';
|
|
523
|
+
return escapeHtml(trimmed);
|
|
524
|
+
}
|
|
525
|
+
if (typeof value === "object") {
|
|
686
526
|
try {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
return `<a class="zenit-popup-link" href="${safeHref}" target="_blank" rel="noopener noreferrer">${safeHref}</a>`;
|
|
691
|
-
}
|
|
527
|
+
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(
|
|
528
|
+
JSON.stringify(value, null, 2)
|
|
529
|
+
)}</pre>`;
|
|
692
530
|
} catch {
|
|
531
|
+
return escapeHtml(String(value));
|
|
693
532
|
}
|
|
694
|
-
return `<span>${escapeHtml(trimmed || value)}</span>`;
|
|
695
|
-
}
|
|
696
|
-
if (typeof value === "object") {
|
|
697
|
-
const json = safeJsonStringify(value);
|
|
698
|
-
return `<pre class="zenit-popup-pre">${escapeHtml(json)}</pre>`;
|
|
699
533
|
}
|
|
700
|
-
return
|
|
534
|
+
return escapeHtml(String(value));
|
|
535
|
+
}
|
|
536
|
+
function extractPopupHeader(properties) {
|
|
537
|
+
const entry = Object.entries(properties).find(([key, value]) => {
|
|
538
|
+
if (typeof value !== "string") return false;
|
|
539
|
+
const normalized = key.trim().toLowerCase();
|
|
540
|
+
return POPUP_HEADER_KEYS.includes(normalized) && value.trim().length > 0;
|
|
541
|
+
});
|
|
542
|
+
return entry ? entry[1].trim() : null;
|
|
701
543
|
}
|
|
702
544
|
function shouldIncludePopupEntry(key, value) {
|
|
703
545
|
if (!key) return false;
|
|
@@ -709,118 +551,480 @@ function shouldIncludePopupEntry(key, value) {
|
|
|
709
551
|
if (typeof value === "string" && !value.trim()) return false;
|
|
710
552
|
return true;
|
|
711
553
|
}
|
|
712
|
-
function
|
|
713
|
-
const
|
|
714
|
-
|
|
554
|
+
function createPopupContent(properties) {
|
|
555
|
+
const headerText = extractPopupHeader(properties);
|
|
556
|
+
const entries = Object.entries(properties).filter(([key, value]) => {
|
|
557
|
+
if (!shouldIncludePopupEntry(key, value)) return false;
|
|
558
|
+
if (headerText && POPUP_HEADER_KEYS.includes(key.trim().toLowerCase())) return false;
|
|
559
|
+
return true;
|
|
560
|
+
});
|
|
561
|
+
if (entries.length === 0) {
|
|
562
|
+
return '<div style="padding:8px 0; color:#64748b; text-align:center;">Sin datos disponibles</div>';
|
|
563
|
+
}
|
|
564
|
+
const headerHtml = headerText ? `<div style="font-weight:700; font-size:14px; margin-bottom:8px; color:#0f172a;">${escapeHtml(
|
|
565
|
+
headerText
|
|
566
|
+
)}</div>` : "";
|
|
567
|
+
const rowsHtml = entries.map(([key, value]) => {
|
|
568
|
+
const label = escapeHtml(formatLabel(key));
|
|
569
|
+
const valueHtml = renderPopupValue(value);
|
|
570
|
+
return `
|
|
571
|
+
<div style="display:grid; grid-template-columns:minmax(90px, 35%) 1fr; gap:8px; padding:6px 0; border-bottom:1px solid #e2e8f0;">
|
|
572
|
+
<div style="font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.04em; color:#64748b;">${label}</div>
|
|
573
|
+
<div style="font-size:13px; color:#0f172a; word-break:break-word;">${valueHtml}</div>
|
|
574
|
+
</div>
|
|
575
|
+
`;
|
|
576
|
+
}).join("");
|
|
577
|
+
return `<div>${headerHtml}${rowsHtml}</div>`;
|
|
715
578
|
}
|
|
716
|
-
function
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
579
|
+
function isPolygonType(layerType, geometryType) {
|
|
580
|
+
const candidate = (layerType ?? geometryType ?? "").toLowerCase();
|
|
581
|
+
return candidate === "polygon" || candidate === "multipolygon";
|
|
582
|
+
}
|
|
583
|
+
function calculateZoomBasedOpacity(zoom, baseOpacity, layerType, geometryType) {
|
|
584
|
+
if (!isPolygonType(layerType, geometryType)) return clampOpacity4(baseOpacity);
|
|
585
|
+
const minZoom = 11;
|
|
586
|
+
const maxZoom = 15;
|
|
587
|
+
const minFactor = 0.3;
|
|
588
|
+
if (maxZoom <= minZoom) return clampOpacity4(baseOpacity * minFactor);
|
|
589
|
+
const t = clampNumber2((zoom - minZoom) / (maxZoom - minZoom), 0, 1);
|
|
590
|
+
const factor = 1 - (1 - minFactor) * t;
|
|
591
|
+
return clampOpacity4(baseOpacity * factor);
|
|
592
|
+
}
|
|
593
|
+
function layerStyleToLeaflet(options) {
|
|
594
|
+
const { baseOpacity, zoom, layerStyle, geometryType, layerType } = options;
|
|
595
|
+
const sanitizedOpacity = clampOpacity4(baseOpacity);
|
|
596
|
+
const zoomOpacity = calculateZoomBasedOpacity(zoom, sanitizedOpacity, layerType, geometryType);
|
|
597
|
+
const styleFillOpacity = typeof layerStyle?.fillOpacity === "number" ? clampOpacity4(layerStyle.fillOpacity) : 0.8;
|
|
598
|
+
return {
|
|
599
|
+
color: layerStyle?.color ?? layerStyle?.fillColor ?? "#2563eb",
|
|
600
|
+
weight: layerStyle?.weight ?? 2,
|
|
601
|
+
fillColor: layerStyle?.fillColor ?? layerStyle?.color ?? "#2563eb",
|
|
602
|
+
opacity: clampOpacity4(Math.max(0.35, zoomOpacity * 0.9)),
|
|
603
|
+
fillOpacity: clampOpacity4(zoomOpacity * styleFillOpacity)
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
function getRgbFromColor(color) {
|
|
607
|
+
const trimmed = color.trim();
|
|
608
|
+
if (trimmed.startsWith("#")) {
|
|
609
|
+
const hex = trimmed.replace("#", "");
|
|
610
|
+
const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
|
|
611
|
+
if (expanded.length === 6) {
|
|
612
|
+
const r = parseInt(expanded.slice(0, 2), 16);
|
|
613
|
+
const g = parseInt(expanded.slice(2, 4), 16);
|
|
614
|
+
const b = parseInt(expanded.slice(4, 6), 16);
|
|
615
|
+
return { r, g, b };
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
const rgbMatch = trimmed.match(/rgba?\(([^)]+)\)/i);
|
|
619
|
+
if (rgbMatch) {
|
|
620
|
+
const [r, g, b] = rgbMatch[1].split(",").map((value) => parseFloat(value.trim())).slice(0, 3);
|
|
621
|
+
if ([r, g, b].every((value) => Number.isFinite(value))) {
|
|
622
|
+
return { r, g, b };
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
function getLabelTextStyles(color) {
|
|
628
|
+
const rgb = getRgbFromColor(color);
|
|
629
|
+
if (!rgb) {
|
|
630
|
+
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.6)" };
|
|
631
|
+
}
|
|
632
|
+
const luminance = (0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b) / 255;
|
|
633
|
+
if (luminance > 0.6) {
|
|
634
|
+
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.7)" };
|
|
635
|
+
}
|
|
636
|
+
return { color: "#ffffff", shadow: "0 1px 2px rgba(0, 0, 0, 0.4)" };
|
|
637
|
+
}
|
|
638
|
+
function withAlpha(color, alpha) {
|
|
639
|
+
const trimmed = color.trim();
|
|
640
|
+
if (trimmed.startsWith("#")) {
|
|
641
|
+
const hex = trimmed.replace("#", "");
|
|
642
|
+
const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
|
|
643
|
+
if (expanded.length === 6) {
|
|
644
|
+
const r = parseInt(expanded.slice(0, 2), 16);
|
|
645
|
+
const g = parseInt(expanded.slice(2, 4), 16);
|
|
646
|
+
const b = parseInt(expanded.slice(4, 6), 16);
|
|
647
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
if (trimmed.startsWith("rgb(")) {
|
|
651
|
+
const inner = trimmed.slice(4, -1);
|
|
652
|
+
return `rgba(${inner}, ${alpha})`;
|
|
653
|
+
}
|
|
654
|
+
if (trimmed.startsWith("rgba(")) {
|
|
655
|
+
const inner = trimmed.slice(5, -1).split(",").slice(0, 3).map((value) => value.trim());
|
|
656
|
+
return `rgba(${inner.join(", ")}, ${alpha})`;
|
|
657
|
+
}
|
|
658
|
+
return color;
|
|
659
|
+
}
|
|
660
|
+
function createCustomIcon(label, opacity, color) {
|
|
661
|
+
const size = 60;
|
|
662
|
+
const innerSize = 44;
|
|
663
|
+
const textStyles = getLabelTextStyles(color);
|
|
664
|
+
const safeLabel = escapeHtml(label);
|
|
665
|
+
const clampedOpacity = Math.min(1, Math.max(0.92, opacity));
|
|
666
|
+
const innerBackground = withAlpha(color, 0.9);
|
|
667
|
+
return L2.divIcon({
|
|
668
|
+
className: "zenit-label-marker",
|
|
669
|
+
iconSize: [size, size],
|
|
670
|
+
iconAnchor: [size / 2, size / 2],
|
|
671
|
+
html: `
|
|
672
|
+
<div
|
|
673
|
+
title="${safeLabel}"
|
|
674
|
+
style="
|
|
675
|
+
width:${size}px;
|
|
676
|
+
height:${size}px;
|
|
677
|
+
border-radius:9999px;
|
|
678
|
+
background:rgba(255, 255, 255, 0.95);
|
|
679
|
+
border:3px solid rgba(255, 255, 255, 1);
|
|
680
|
+
display:flex;
|
|
681
|
+
align-items:center;
|
|
682
|
+
justify-content:center;
|
|
683
|
+
opacity:${clampedOpacity};
|
|
684
|
+
box-shadow:0 2px 6px rgba(0, 0, 0, 0.25);
|
|
685
|
+
pointer-events:none;
|
|
686
|
+
"
|
|
687
|
+
>
|
|
688
|
+
<div
|
|
689
|
+
style="
|
|
690
|
+
width:${innerSize}px;
|
|
691
|
+
height:${innerSize}px;
|
|
692
|
+
border-radius:9999px;
|
|
693
|
+
background:${innerBackground};
|
|
694
|
+
display:flex;
|
|
695
|
+
align-items:center;
|
|
696
|
+
justify-content:center;
|
|
697
|
+
box-shadow:inset 0 0 0 1px rgba(15, 23, 42, 0.12);
|
|
698
|
+
"
|
|
699
|
+
>
|
|
700
|
+
<span
|
|
701
|
+
style="
|
|
702
|
+
color:${textStyles.color};
|
|
703
|
+
font-size:20px;
|
|
704
|
+
font-weight:800;
|
|
705
|
+
text-shadow:${textStyles.shadow};
|
|
706
|
+
"
|
|
707
|
+
>
|
|
708
|
+
${safeLabel}
|
|
709
|
+
</span>
|
|
710
|
+
</div>
|
|
711
|
+
</div>
|
|
712
|
+
`
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
function createLocationIcon() {
|
|
716
|
+
return L2.divIcon({
|
|
717
|
+
className: "zenit-location-marker",
|
|
718
|
+
iconSize: [18, 18],
|
|
719
|
+
iconAnchor: [9, 9],
|
|
720
|
+
html: `
|
|
721
|
+
<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>
|
|
722
|
+
`
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// src/react/map/location-control.tsx
|
|
727
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
728
|
+
var LOCATION_STYLE_ID = "zenit-location-control-styles";
|
|
729
|
+
var LOCATION_STYLES = `
|
|
730
|
+
.zenit-location-control {
|
|
731
|
+
display: flex;
|
|
732
|
+
flex-direction: column;
|
|
733
|
+
gap: 8px;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
.zenit-location-button {
|
|
737
|
+
width: 42px;
|
|
738
|
+
height: 42px;
|
|
739
|
+
border-radius: 12px;
|
|
740
|
+
border: none;
|
|
741
|
+
background: #ffffff;
|
|
742
|
+
color: #0f172a;
|
|
743
|
+
box-shadow: 0 8px 18px rgba(15, 23, 42, 0.2);
|
|
744
|
+
display: inline-flex;
|
|
745
|
+
align-items: center;
|
|
746
|
+
justify-content: center;
|
|
747
|
+
cursor: pointer;
|
|
748
|
+
position: relative;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
.zenit-location-button.zenit-location-button--tracking {
|
|
752
|
+
animation: zenitLocationPulse 1.8s infinite;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
.zenit-location-button:hover {
|
|
756
|
+
background: #f8fafc;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
.zenit-location-badge {
|
|
760
|
+
position: absolute;
|
|
761
|
+
top: -6px;
|
|
762
|
+
right: -6px;
|
|
763
|
+
width: 18px;
|
|
764
|
+
height: 18px;
|
|
765
|
+
border-radius: 999px;
|
|
766
|
+
background: #ef4444;
|
|
767
|
+
color: #fff;
|
|
768
|
+
font-size: 11px;
|
|
769
|
+
font-weight: 700;
|
|
770
|
+
display: inline-flex;
|
|
771
|
+
align-items: center;
|
|
772
|
+
justify-content: center;
|
|
773
|
+
box-shadow: 0 4px 10px rgba(239, 68, 68, 0.35);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
.zenit-location-error {
|
|
777
|
+
background: rgba(15, 23, 42, 0.92);
|
|
778
|
+
color: #f8fafc;
|
|
779
|
+
border-radius: 10px;
|
|
780
|
+
padding: 8px 10px;
|
|
781
|
+
font-size: 12px;
|
|
782
|
+
max-width: 200px;
|
|
783
|
+
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.3);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
@keyframes zenitLocationPulse {
|
|
787
|
+
0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.35); }
|
|
788
|
+
70% { box-shadow: 0 0 0 12px rgba(16, 185, 129, 0); }
|
|
789
|
+
100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
|
|
790
|
+
}
|
|
791
|
+
`;
|
|
792
|
+
var LocateIcon = () => /* @__PURE__ */ jsxs2("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
793
|
+
/* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "3" }),
|
|
794
|
+
/* @__PURE__ */ jsx2("line", { x1: "12", y1: "2", x2: "12", y2: "5" }),
|
|
795
|
+
/* @__PURE__ */ jsx2("line", { x1: "12", y1: "19", x2: "12", y2: "22" }),
|
|
796
|
+
/* @__PURE__ */ jsx2("line", { x1: "2", y1: "12", x2: "5", y2: "12" }),
|
|
797
|
+
/* @__PURE__ */ jsx2("line", { x1: "19", y1: "12", x2: "22", y2: "12" })
|
|
798
|
+
] });
|
|
799
|
+
var LocationControl = ({ position = "bottomleft", zoom = 16 }) => {
|
|
800
|
+
const map = useMap();
|
|
801
|
+
const controlRef = useRef2(null);
|
|
802
|
+
const hasCenteredRef = useRef2(false);
|
|
803
|
+
const { isTracking, location, error, toggleTracking, clearError } = useGeolocation();
|
|
804
|
+
useEffect2(() => {
|
|
805
|
+
if (typeof document === "undefined") return;
|
|
806
|
+
if (document.getElementById(LOCATION_STYLE_ID)) return;
|
|
807
|
+
const styleTag = document.createElement("style");
|
|
808
|
+
styleTag.id = LOCATION_STYLE_ID;
|
|
809
|
+
styleTag.textContent = LOCATION_STYLES;
|
|
810
|
+
document.head.appendChild(styleTag);
|
|
811
|
+
}, []);
|
|
812
|
+
useEffect2(() => {
|
|
813
|
+
const control = L3.control({ position });
|
|
814
|
+
control.onAdd = () => {
|
|
815
|
+
const container = L3.DomUtil.create("div", "zenit-location-control");
|
|
816
|
+
L3.DomEvent.disableClickPropagation(container);
|
|
817
|
+
controlRef.current = container;
|
|
818
|
+
return container;
|
|
819
|
+
};
|
|
820
|
+
control.addTo(map);
|
|
821
|
+
return () => {
|
|
822
|
+
control.remove();
|
|
823
|
+
controlRef.current = null;
|
|
824
|
+
};
|
|
825
|
+
}, [map, position]);
|
|
826
|
+
useEffect2(() => {
|
|
827
|
+
if (!location || !isTracking) return;
|
|
828
|
+
if (hasCenteredRef.current) return;
|
|
829
|
+
hasCenteredRef.current = true;
|
|
830
|
+
map.flyTo([location.lat, location.lon], zoom, { animate: true });
|
|
831
|
+
}, [isTracking, location, map, zoom]);
|
|
832
|
+
const markerIcon = useMemo(() => createLocationIcon(), []);
|
|
833
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
834
|
+
controlRef.current && createPortal(
|
|
835
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
836
|
+
/* @__PURE__ */ jsxs2(
|
|
837
|
+
"button",
|
|
838
|
+
{
|
|
839
|
+
type: "button",
|
|
840
|
+
className: `zenit-location-button${isTracking ? " zenit-location-button--tracking" : ""}`,
|
|
841
|
+
onClick: () => {
|
|
842
|
+
if (error) {
|
|
843
|
+
clearError();
|
|
844
|
+
}
|
|
845
|
+
toggleTracking();
|
|
846
|
+
},
|
|
847
|
+
"aria-label": isTracking ? "Detener ubicaci\xF3n" : "Mostrar mi ubicaci\xF3n",
|
|
848
|
+
children: [
|
|
849
|
+
/* @__PURE__ */ jsx2(LocateIcon, {}),
|
|
850
|
+
error && /* @__PURE__ */ jsx2("span", { className: "zenit-location-badge", children: "!" })
|
|
851
|
+
]
|
|
852
|
+
}
|
|
853
|
+
),
|
|
854
|
+
error && /* @__PURE__ */ jsx2("div", { className: "zenit-location-error", children: error.message || "No se pudo acceder a tu ubicaci\xF3n." })
|
|
855
|
+
] }),
|
|
856
|
+
controlRef.current
|
|
857
|
+
),
|
|
858
|
+
location && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
859
|
+
/* @__PURE__ */ jsx2(Marker, { position: [location.lat, location.lon], icon: markerIcon }),
|
|
860
|
+
/* @__PURE__ */ jsx2(
|
|
861
|
+
Circle,
|
|
862
|
+
{
|
|
863
|
+
center: [location.lat, location.lon],
|
|
864
|
+
radius: location.accuracy,
|
|
865
|
+
pathOptions: { color: "#2563eb", fillColor: "#2563eb", fillOpacity: 0.15 }
|
|
866
|
+
}
|
|
867
|
+
)
|
|
868
|
+
] })
|
|
869
|
+
] });
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
// src/react/map/map-handlers.tsx
|
|
873
|
+
import { useEffect as useEffect3, useRef as useRef3 } from "react";
|
|
874
|
+
import { useMap as useMap2 } from "react-leaflet";
|
|
875
|
+
function computeBBoxFromGeojson(geojson) {
|
|
876
|
+
if (!geojson || !Array.isArray(geojson.features)) return null;
|
|
877
|
+
const coords = [];
|
|
878
|
+
const collect = (candidate) => {
|
|
879
|
+
if (!Array.isArray(candidate)) return;
|
|
880
|
+
if (candidate.length === 2 && typeof candidate[0] === "number" && typeof candidate[1] === "number" && Number.isFinite(candidate[0]) && Number.isFinite(candidate[1])) {
|
|
881
|
+
coords.push([candidate[0], candidate[1]]);
|
|
882
|
+
return;
|
|
722
883
|
}
|
|
884
|
+
candidate.forEach((item) => collect(item));
|
|
885
|
+
};
|
|
886
|
+
geojson.features.forEach((feature) => {
|
|
887
|
+
collect(feature.geometry?.coordinates);
|
|
888
|
+
});
|
|
889
|
+
if (coords.length === 0) return null;
|
|
890
|
+
const [firstLon, firstLat] = coords[0];
|
|
891
|
+
const bbox = { minLon: firstLon, minLat: firstLat, maxLon: firstLon, maxLat: firstLat };
|
|
892
|
+
coords.forEach(([lon, lat]) => {
|
|
893
|
+
bbox.minLon = Math.min(bbox.minLon, lon);
|
|
894
|
+
bbox.minLat = Math.min(bbox.minLat, lat);
|
|
895
|
+
bbox.maxLon = Math.max(bbox.maxLon, lon);
|
|
896
|
+
bbox.maxLat = Math.max(bbox.maxLat, lat);
|
|
897
|
+
});
|
|
898
|
+
return bbox;
|
|
899
|
+
}
|
|
900
|
+
function mergeBBoxes(bboxes) {
|
|
901
|
+
const valid = bboxes.filter((bbox) => !!bbox);
|
|
902
|
+
if (valid.length === 0) return null;
|
|
903
|
+
const first = valid[0];
|
|
904
|
+
return valid.slice(1).reduce(
|
|
905
|
+
(acc, bbox) => ({
|
|
906
|
+
minLon: Math.min(acc.minLon, bbox.minLon),
|
|
907
|
+
minLat: Math.min(acc.minLat, bbox.minLat),
|
|
908
|
+
maxLon: Math.max(acc.maxLon, bbox.maxLon),
|
|
909
|
+
maxLat: Math.max(acc.maxLat, bbox.maxLat)
|
|
910
|
+
}),
|
|
911
|
+
{ ...first }
|
|
723
912
|
);
|
|
724
|
-
if (!entry) return null;
|
|
725
|
-
return entry[1].trim();
|
|
726
913
|
}
|
|
727
|
-
|
|
728
|
-
|
|
914
|
+
var BBoxZoomHandler = ({
|
|
915
|
+
bbox,
|
|
916
|
+
geojson,
|
|
917
|
+
autoGeojson = [],
|
|
918
|
+
enabled = true
|
|
919
|
+
}) => {
|
|
920
|
+
const map = useMap2();
|
|
921
|
+
const lastAppliedBBox = useRef3(null);
|
|
922
|
+
const lastUserInteracted = useRef3(false);
|
|
923
|
+
useEffect3(() => {
|
|
924
|
+
const handleInteraction = () => {
|
|
925
|
+
lastUserInteracted.current = true;
|
|
926
|
+
};
|
|
927
|
+
map.on("dragstart", handleInteraction);
|
|
928
|
+
map.on("zoomstart", handleInteraction);
|
|
929
|
+
return () => {
|
|
930
|
+
map.off("dragstart", handleInteraction);
|
|
931
|
+
map.off("zoomstart", handleInteraction);
|
|
932
|
+
};
|
|
933
|
+
}, [map]);
|
|
934
|
+
useEffect3(() => {
|
|
935
|
+
if (!enabled) return;
|
|
936
|
+
let resolvedBBox = bbox ?? null;
|
|
937
|
+
if (!resolvedBBox && geojson) {
|
|
938
|
+
resolvedBBox = computeBBoxFromGeojson(geojson);
|
|
939
|
+
}
|
|
940
|
+
if (!resolvedBBox && autoGeojson.length > 0) {
|
|
941
|
+
const bboxes = autoGeojson.map((collection) => computeBBoxFromGeojson(collection));
|
|
942
|
+
resolvedBBox = mergeBBoxes(bboxes);
|
|
943
|
+
}
|
|
944
|
+
if (!resolvedBBox) return;
|
|
945
|
+
const serialized = JSON.stringify(resolvedBBox);
|
|
946
|
+
if (lastAppliedBBox.current === serialized) return;
|
|
947
|
+
if (lastUserInteracted.current && !bbox && !geojson) {
|
|
948
|
+
lastUserInteracted.current = false;
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
const bounds = [
|
|
952
|
+
[resolvedBBox.minLat, resolvedBBox.minLon],
|
|
953
|
+
[resolvedBBox.maxLat, resolvedBBox.maxLon]
|
|
954
|
+
];
|
|
955
|
+
map.fitBounds(bounds, { padding: [12, 12] });
|
|
956
|
+
lastAppliedBBox.current = serialized;
|
|
957
|
+
}, [autoGeojson, bbox, enabled, geojson, map]);
|
|
958
|
+
return null;
|
|
959
|
+
};
|
|
960
|
+
var ZoomBasedOpacityHandler = ({ onZoomChange }) => {
|
|
961
|
+
const map = useMap2();
|
|
962
|
+
useEffect3(() => {
|
|
963
|
+
const handleZoom = () => {
|
|
964
|
+
onZoomChange(map.getZoom());
|
|
965
|
+
};
|
|
966
|
+
map.on("zoomend", handleZoom);
|
|
967
|
+
handleZoom();
|
|
968
|
+
return () => {
|
|
969
|
+
map.off("zoomend", handleZoom);
|
|
970
|
+
};
|
|
971
|
+
}, [map, onZoomChange]);
|
|
972
|
+
return null;
|
|
973
|
+
};
|
|
974
|
+
var MapInstanceBridge = ({ onReady }) => {
|
|
975
|
+
const map = useMap2();
|
|
976
|
+
useEffect3(() => {
|
|
977
|
+
onReady(map);
|
|
978
|
+
}, [map, onReady]);
|
|
979
|
+
return null;
|
|
980
|
+
};
|
|
981
|
+
|
|
982
|
+
// src/react/ZenitMap.tsx
|
|
983
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
984
|
+
var DEFAULT_CENTER = [0, 0];
|
|
985
|
+
var DEFAULT_ZOOM = 3;
|
|
986
|
+
var LABELS_PANE_NAME = "zenit-labels-pane";
|
|
987
|
+
function isRecord(value) {
|
|
988
|
+
return typeof value === "object" && value !== null;
|
|
989
|
+
}
|
|
990
|
+
function isGeoJsonFeatureCollection(value) {
|
|
991
|
+
if (!isRecord(value)) return false;
|
|
992
|
+
const features = value.features;
|
|
993
|
+
if (!Array.isArray(features)) return false;
|
|
994
|
+
const type = value.type;
|
|
995
|
+
return type === void 0 || type === "FeatureCollection";
|
|
729
996
|
}
|
|
730
|
-
function
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
if (headerText && POPUP_HEADER_KEYS.includes(key.trim().toLowerCase())) {
|
|
735
|
-
return false;
|
|
736
|
-
}
|
|
737
|
-
return true;
|
|
738
|
-
});
|
|
739
|
-
if (entries.length === 0) {
|
|
740
|
-
return `<div class="zenit-popup-card"><div class="zenit-popup-empty">Sin datos disponibles</div></div>`;
|
|
741
|
-
}
|
|
742
|
-
const descriptionEntry = entries.find(([key]) => isDescriptionKey(key));
|
|
743
|
-
const otherEntries = entries.filter(([key]) => !isDescriptionKey(key));
|
|
744
|
-
let rowsHtml = "";
|
|
745
|
-
if (descriptionEntry) {
|
|
746
|
-
const [key, value] = descriptionEntry;
|
|
747
|
-
const label = escapeHtml(formatLabel(key));
|
|
748
|
-
const valueHtml = renderPopupValue(value);
|
|
749
|
-
rowsHtml += `
|
|
750
|
-
<div class="zenit-popup-row zenit-popup-description">
|
|
751
|
-
<div class="zenit-popup-label">${label}</div>
|
|
752
|
-
<div class="zenit-popup-value">${valueHtml}</div>
|
|
753
|
-
</div>
|
|
754
|
-
`;
|
|
997
|
+
function extractGeoJsonFeatureCollection(value) {
|
|
998
|
+
if (isRecord(value) && "data" in value) {
|
|
999
|
+
const data = value.data;
|
|
1000
|
+
return isGeoJsonFeatureCollection(data) ? data : null;
|
|
755
1001
|
}
|
|
756
|
-
|
|
757
|
-
const label = escapeHtml(formatLabel(key));
|
|
758
|
-
const valueHtml = renderPopupValue(value);
|
|
759
|
-
return `
|
|
760
|
-
<div class="zenit-popup-row">
|
|
761
|
-
<div class="zenit-popup-label">${label}</div>
|
|
762
|
-
<div class="zenit-popup-value">${valueHtml}</div>
|
|
763
|
-
</div>
|
|
764
|
-
`;
|
|
765
|
-
}).join("");
|
|
766
|
-
const headerHtml = headerText ? `<div class="zenit-popup-header"><div class="zenit-popup-title">${escapeHtml(
|
|
767
|
-
headerText
|
|
768
|
-
)}</div></div>` : "";
|
|
769
|
-
return `<div class="zenit-popup-card">${headerHtml}${rowsHtml}</div>`;
|
|
1002
|
+
return isGeoJsonFeatureCollection(value) ? value : null;
|
|
770
1003
|
}
|
|
771
|
-
function
|
|
772
|
-
const
|
|
773
|
-
if (
|
|
774
|
-
|
|
775
|
-
const expanded = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
|
|
776
|
-
if (expanded.length === 6) {
|
|
777
|
-
const r = parseInt(expanded.slice(0, 2), 16);
|
|
778
|
-
const g = parseInt(expanded.slice(2, 4), 16);
|
|
779
|
-
const b = parseInt(expanded.slice(4, 6), 16);
|
|
780
|
-
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
if (trimmed.startsWith("rgb(")) {
|
|
784
|
-
const inner = trimmed.slice(4, -1);
|
|
785
|
-
return `rgba(${inner}, ${alpha})`;
|
|
786
|
-
}
|
|
787
|
-
if (trimmed.startsWith("rgba(")) {
|
|
788
|
-
const inner = trimmed.slice(5, -1).split(",").slice(0, 3).map((value) => value.trim());
|
|
789
|
-
return `rgba(${inner.join(", ")}, ${alpha})`;
|
|
790
|
-
}
|
|
791
|
-
return color;
|
|
1004
|
+
function getFeatureLayerId(feature) {
|
|
1005
|
+
const layerId = feature?.properties?.__zenit_layerId ?? feature?.properties?.layerId ?? feature?.properties?.layer_id;
|
|
1006
|
+
if (layerId === void 0 || layerId === null) return null;
|
|
1007
|
+
return layerId;
|
|
792
1008
|
}
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
if (
|
|
796
|
-
|
|
797
|
-
const
|
|
798
|
-
|
|
799
|
-
const r = parseInt(expanded.slice(0, 2), 16);
|
|
800
|
-
const g = parseInt(expanded.slice(2, 4), 16);
|
|
801
|
-
const b = parseInt(expanded.slice(4, 6), 16);
|
|
802
|
-
return { r, g, b };
|
|
803
|
-
}
|
|
1009
|
+
var DESCRIPTION_KEYS = /* @__PURE__ */ new Set(["descripcion", "description"]);
|
|
1010
|
+
function normalizeDescriptionValue(value) {
|
|
1011
|
+
if (value === void 0 || value === null) return null;
|
|
1012
|
+
if (typeof value === "string") {
|
|
1013
|
+
const trimmed = value.trim();
|
|
1014
|
+
return trimmed ? trimmed : null;
|
|
804
1015
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
const [r, g, b] = rgbMatch[1].split(",").map((value) => parseFloat(value.trim())).slice(0, 3);
|
|
808
|
-
if ([r, g, b].every((value) => Number.isFinite(value))) {
|
|
809
|
-
return { r, g, b };
|
|
810
|
-
}
|
|
1016
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
1017
|
+
return String(value);
|
|
811
1018
|
}
|
|
812
1019
|
return null;
|
|
813
1020
|
}
|
|
814
|
-
function
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
return { color: "#0f172a", shadow: "0 1px 2px rgba(255, 255, 255, 0.7)" };
|
|
822
|
-
}
|
|
823
|
-
return { color: "#ffffff", shadow: "0 1px 2px rgba(0, 0, 0, 0.4)" };
|
|
1021
|
+
function extractDescriptionValue(properties) {
|
|
1022
|
+
if (!properties) return null;
|
|
1023
|
+
const matches = Object.entries(properties).find(
|
|
1024
|
+
([key]) => DESCRIPTION_KEYS.has(key.toLowerCase())
|
|
1025
|
+
);
|
|
1026
|
+
if (!matches) return null;
|
|
1027
|
+
return normalizeDescriptionValue(matches[1]);
|
|
824
1028
|
}
|
|
825
1029
|
function getFeatureStyleOverrides(feature) {
|
|
826
1030
|
const candidate = feature?.properties?._style;
|
|
@@ -839,25 +1043,6 @@ function buildFeaturePopupHtml(feature) {
|
|
|
839
1043
|
const rendered = createPopupContent(properties);
|
|
840
1044
|
return rendered ? rendered : null;
|
|
841
1045
|
}
|
|
842
|
-
var POINT_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["Point", "MultiPoint"]);
|
|
843
|
-
function getGeometryType(feature) {
|
|
844
|
-
const t = feature?.geometry?.type;
|
|
845
|
-
return typeof t === "string" ? t : null;
|
|
846
|
-
}
|
|
847
|
-
function isPointGeometry(feature) {
|
|
848
|
-
const geometryType = getGeometryType(feature);
|
|
849
|
-
return geometryType !== null && POINT_GEOMETRY_TYPES.has(geometryType);
|
|
850
|
-
}
|
|
851
|
-
function isNonPointGeometry(feature) {
|
|
852
|
-
const geometryType = getGeometryType(feature);
|
|
853
|
-
return geometryType !== null && !POINT_GEOMETRY_TYPES.has(geometryType);
|
|
854
|
-
}
|
|
855
|
-
function buildFeatureCollection(features) {
|
|
856
|
-
return {
|
|
857
|
-
type: "FeatureCollection",
|
|
858
|
-
features
|
|
859
|
-
};
|
|
860
|
-
}
|
|
861
1046
|
function pickIntersectFeature(baseFeature, candidates) {
|
|
862
1047
|
if (!Array.isArray(candidates) || candidates.length === 0) return null;
|
|
863
1048
|
const baseId = baseFeature?.id;
|
|
@@ -884,80 +1069,6 @@ function normalizeCenterTuple(center) {
|
|
|
884
1069
|
}
|
|
885
1070
|
return null;
|
|
886
1071
|
}
|
|
887
|
-
var FitToBounds = ({ bbox }) => {
|
|
888
|
-
const mapInstance = useMap();
|
|
889
|
-
const lastAppliedBBox = useRef(null);
|
|
890
|
-
useEffect(() => {
|
|
891
|
-
const targetBBox = bbox;
|
|
892
|
-
if (!targetBBox) return;
|
|
893
|
-
const serialized = JSON.stringify(targetBBox);
|
|
894
|
-
if (lastAppliedBBox.current === serialized) return;
|
|
895
|
-
const bounds = [
|
|
896
|
-
[targetBBox.minLat, targetBBox.minLon],
|
|
897
|
-
[targetBBox.maxLat, targetBBox.maxLon]
|
|
898
|
-
];
|
|
899
|
-
mapInstance.fitBounds(bounds, { padding: [12, 12] });
|
|
900
|
-
lastAppliedBBox.current = serialized;
|
|
901
|
-
}, [bbox, mapInstance]);
|
|
902
|
-
return null;
|
|
903
|
-
};
|
|
904
|
-
var AutoFitToBounds = ({
|
|
905
|
-
bbox,
|
|
906
|
-
enabled = true
|
|
907
|
-
}) => {
|
|
908
|
-
const mapInstance = useMap();
|
|
909
|
-
const lastAutoBBoxApplied = useRef(null);
|
|
910
|
-
const lastUserInteracted = useRef(false);
|
|
911
|
-
useEffect(() => {
|
|
912
|
-
if (!enabled) return;
|
|
913
|
-
const handleInteraction = () => {
|
|
914
|
-
lastUserInteracted.current = true;
|
|
915
|
-
};
|
|
916
|
-
mapInstance.on("dragstart", handleInteraction);
|
|
917
|
-
mapInstance.on("zoomstart", handleInteraction);
|
|
918
|
-
return () => {
|
|
919
|
-
mapInstance.off("dragstart", handleInteraction);
|
|
920
|
-
mapInstance.off("zoomstart", handleInteraction);
|
|
921
|
-
};
|
|
922
|
-
}, [enabled, mapInstance]);
|
|
923
|
-
useEffect(() => {
|
|
924
|
-
if (!enabled) return;
|
|
925
|
-
if (!bbox) return;
|
|
926
|
-
const serialized = JSON.stringify(bbox);
|
|
927
|
-
if (lastAutoBBoxApplied.current === serialized) return;
|
|
928
|
-
if (lastUserInteracted.current) {
|
|
929
|
-
lastUserInteracted.current = false;
|
|
930
|
-
}
|
|
931
|
-
const bounds = [
|
|
932
|
-
[bbox.minLat, bbox.minLon],
|
|
933
|
-
[bbox.maxLat, bbox.maxLon]
|
|
934
|
-
];
|
|
935
|
-
mapInstance.fitBounds(bounds, { padding: [12, 12] });
|
|
936
|
-
lastAutoBBoxApplied.current = serialized;
|
|
937
|
-
}, [bbox, enabled, mapInstance]);
|
|
938
|
-
return null;
|
|
939
|
-
};
|
|
940
|
-
var ZoomBasedOpacityHandler = ({ onZoomChange }) => {
|
|
941
|
-
const mapInstance = useMap();
|
|
942
|
-
useEffect(() => {
|
|
943
|
-
const handleZoom = () => {
|
|
944
|
-
onZoomChange(mapInstance.getZoom());
|
|
945
|
-
};
|
|
946
|
-
mapInstance.on("zoomend", handleZoom);
|
|
947
|
-
handleZoom();
|
|
948
|
-
return () => {
|
|
949
|
-
mapInstance.off("zoomend", handleZoom);
|
|
950
|
-
};
|
|
951
|
-
}, [mapInstance, onZoomChange]);
|
|
952
|
-
return null;
|
|
953
|
-
};
|
|
954
|
-
var MapInstanceBridge = ({ onReady }) => {
|
|
955
|
-
const mapInstance = useMap();
|
|
956
|
-
useEffect(() => {
|
|
957
|
-
onReady(mapInstance);
|
|
958
|
-
}, [mapInstance, onReady]);
|
|
959
|
-
return null;
|
|
960
|
-
};
|
|
961
1072
|
var ZenitMap = forwardRef(({
|
|
962
1073
|
client,
|
|
963
1074
|
mapId,
|
|
@@ -983,21 +1094,21 @@ var ZenitMap = forwardRef(({
|
|
|
983
1094
|
onZoomChange,
|
|
984
1095
|
onMapReady
|
|
985
1096
|
}, ref) => {
|
|
986
|
-
const [map, setMap] =
|
|
987
|
-
const [layers, setLayers] =
|
|
988
|
-
const [effectiveStates, setEffectiveStates] =
|
|
989
|
-
const [loadingMap, setLoadingMap] =
|
|
990
|
-
const [mapError, setMapError] =
|
|
991
|
-
const [mapInstance, setMapInstance] =
|
|
992
|
-
const [panesReady, setPanesReady] =
|
|
993
|
-
const [currentZoom, setCurrentZoom] =
|
|
994
|
-
const [isPopupOpen, setIsPopupOpen] =
|
|
995
|
-
const [isMobile, setIsMobile] =
|
|
1097
|
+
const [map, setMap] = useState2(null);
|
|
1098
|
+
const [layers, setLayers] = useState2([]);
|
|
1099
|
+
const [effectiveStates, setEffectiveStates] = useState2([]);
|
|
1100
|
+
const [loadingMap, setLoadingMap] = useState2(false);
|
|
1101
|
+
const [mapError, setMapError] = useState2(null);
|
|
1102
|
+
const [mapInstance, setMapInstance] = useState2(null);
|
|
1103
|
+
const [panesReady, setPanesReady] = useState2(false);
|
|
1104
|
+
const [currentZoom, setCurrentZoom] = useState2(initialZoom ?? DEFAULT_ZOOM);
|
|
1105
|
+
const [isPopupOpen, setIsPopupOpen] = useState2(false);
|
|
1106
|
+
const [isMobile, setIsMobile] = useState2(() => {
|
|
996
1107
|
if (typeof window === "undefined") return false;
|
|
997
1108
|
return window.matchMedia("(max-width: 768px)").matches;
|
|
998
1109
|
});
|
|
999
|
-
const normalizedLayers =
|
|
1000
|
-
|
|
1110
|
+
const normalizedLayers = useMemo2(() => normalizeMapLayers(map), [map]);
|
|
1111
|
+
useEffect4(() => {
|
|
1001
1112
|
if (typeof window === "undefined") return;
|
|
1002
1113
|
const mql = window.matchMedia("(max-width: 768px)");
|
|
1003
1114
|
const onChange = (e) => {
|
|
@@ -1015,17 +1126,17 @@ var ZenitMap = forwardRef(({
|
|
|
1015
1126
|
}
|
|
1016
1127
|
return;
|
|
1017
1128
|
}, []);
|
|
1018
|
-
|
|
1129
|
+
useEffect4(() => {
|
|
1019
1130
|
if (featureInfoMode === "popup") {
|
|
1020
1131
|
ensurePopupStyles();
|
|
1021
1132
|
}
|
|
1022
1133
|
}, [featureInfoMode]);
|
|
1023
|
-
|
|
1134
|
+
useEffect4(() => {
|
|
1024
1135
|
if (featureInfoMode !== "popup") {
|
|
1025
1136
|
setIsPopupOpen(false);
|
|
1026
1137
|
}
|
|
1027
1138
|
}, [featureInfoMode]);
|
|
1028
|
-
|
|
1139
|
+
useEffect4(() => {
|
|
1029
1140
|
if (!mapInstance) return;
|
|
1030
1141
|
const popupPane = mapInstance.getPane("popupPane");
|
|
1031
1142
|
if (popupPane) {
|
|
@@ -1034,7 +1145,7 @@ var ZenitMap = forwardRef(({
|
|
|
1034
1145
|
const labelsPane = mapInstance.getPane(LABELS_PANE_NAME) ?? mapInstance.createPane(LABELS_PANE_NAME);
|
|
1035
1146
|
labelsPane.style.zIndex = "600";
|
|
1036
1147
|
}, [mapInstance]);
|
|
1037
|
-
|
|
1148
|
+
useEffect4(() => {
|
|
1038
1149
|
if (!mapInstance) return;
|
|
1039
1150
|
const handlePopupOpen = () => setIsPopupOpen(true);
|
|
1040
1151
|
const handlePopupClose = () => setIsPopupOpen(false);
|
|
@@ -1045,7 +1156,7 @@ var ZenitMap = forwardRef(({
|
|
|
1045
1156
|
mapInstance.off("popupclose", handlePopupClose);
|
|
1046
1157
|
};
|
|
1047
1158
|
}, [mapInstance]);
|
|
1048
|
-
const layerStyleIndex =
|
|
1159
|
+
const layerStyleIndex = useMemo2(() => {
|
|
1049
1160
|
const index = /* @__PURE__ */ new Map();
|
|
1050
1161
|
(map?.mapLayers ?? []).forEach((entry) => {
|
|
1051
1162
|
const layerStyle = entry.layer?.style ?? entry.mapLayer?.layer?.style ?? entry.style ?? null;
|
|
@@ -1056,7 +1167,7 @@ var ZenitMap = forwardRef(({
|
|
|
1056
1167
|
});
|
|
1057
1168
|
return index;
|
|
1058
1169
|
}, [map]);
|
|
1059
|
-
const labelKeyIndex =
|
|
1170
|
+
const labelKeyIndex = useMemo2(() => {
|
|
1060
1171
|
const index = /* @__PURE__ */ new Map();
|
|
1061
1172
|
normalizedLayers.forEach((entry) => {
|
|
1062
1173
|
const label = entry.layer?.label ?? entry.mapLayer?.label ?? entry.mapLayer.layerConfig?.label;
|
|
@@ -1066,7 +1177,7 @@ var ZenitMap = forwardRef(({
|
|
|
1066
1177
|
});
|
|
1067
1178
|
return index;
|
|
1068
1179
|
}, [normalizedLayers]);
|
|
1069
|
-
const layerMetaIndex =
|
|
1180
|
+
const layerMetaIndex = useMemo2(() => {
|
|
1070
1181
|
const index = /* @__PURE__ */ new Map();
|
|
1071
1182
|
normalizedLayers.forEach((entry) => {
|
|
1072
1183
|
index.set(String(entry.layerId), {
|
|
@@ -1076,7 +1187,7 @@ var ZenitMap = forwardRef(({
|
|
|
1076
1187
|
});
|
|
1077
1188
|
return index;
|
|
1078
1189
|
}, [normalizedLayers]);
|
|
1079
|
-
const overlayStyleFunction =
|
|
1190
|
+
const overlayStyleFunction = useMemo2(() => {
|
|
1080
1191
|
return (feature) => {
|
|
1081
1192
|
const featureLayerId = getFeatureLayerId(feature);
|
|
1082
1193
|
const featureStyleOverrides = getFeatureStyleOverrides(feature);
|
|
@@ -1095,11 +1206,15 @@ var ZenitMap = forwardRef(({
|
|
|
1095
1206
|
return defaultOptions;
|
|
1096
1207
|
};
|
|
1097
1208
|
}, [layerStyleIndex, mapLayers, overlayStyle]);
|
|
1098
|
-
const
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1209
|
+
const overlayStyleFn = useCallback2(
|
|
1210
|
+
(feature, _layerType, _baseOpacity) => overlayStyleFunction(feature),
|
|
1211
|
+
[overlayStyleFunction]
|
|
1212
|
+
);
|
|
1213
|
+
const [baseStates, setBaseStates] = useState2([]);
|
|
1214
|
+
const [mapOverrides, setMapOverrides] = useState2([]);
|
|
1215
|
+
const [controlOverrides, setControlOverrides] = useState2([]);
|
|
1216
|
+
const [uiOverrides, setUiOverrides] = useState2([]);
|
|
1217
|
+
useEffect4(() => {
|
|
1103
1218
|
let isMounted = true;
|
|
1104
1219
|
setLoadingMap(true);
|
|
1105
1220
|
setMapError(null);
|
|
@@ -1122,7 +1237,7 @@ var ZenitMap = forwardRef(({
|
|
|
1122
1237
|
isMounted = false;
|
|
1123
1238
|
};
|
|
1124
1239
|
}, [client.maps, mapId, onError, onLoadingChange]);
|
|
1125
|
-
|
|
1240
|
+
useEffect4(() => {
|
|
1126
1241
|
if (normalizedLayers.length === 0) {
|
|
1127
1242
|
setLayers([]);
|
|
1128
1243
|
setBaseStates([]);
|
|
@@ -1153,7 +1268,7 @@ var ZenitMap = forwardRef(({
|
|
|
1153
1268
|
setMapOverrides(initialOverrides);
|
|
1154
1269
|
setUiOverrides([]);
|
|
1155
1270
|
}, [normalizedLayers]);
|
|
1156
|
-
|
|
1271
|
+
useEffect4(() => {
|
|
1157
1272
|
if (!layerControls) {
|
|
1158
1273
|
setControlOverrides([]);
|
|
1159
1274
|
return;
|
|
@@ -1165,7 +1280,7 @@ var ZenitMap = forwardRef(({
|
|
|
1165
1280
|
}));
|
|
1166
1281
|
setControlOverrides(overrides);
|
|
1167
1282
|
}, [layerControls]);
|
|
1168
|
-
|
|
1283
|
+
useEffect4(() => {
|
|
1169
1284
|
if (layerStates) {
|
|
1170
1285
|
return;
|
|
1171
1286
|
}
|
|
@@ -1175,12 +1290,12 @@ var ZenitMap = forwardRef(({
|
|
|
1175
1290
|
onLayerStateChange?.(reset);
|
|
1176
1291
|
}
|
|
1177
1292
|
}, [baseStates, effectiveStates.length, layerControls, layerStates, onLayerStateChange]);
|
|
1178
|
-
|
|
1293
|
+
useEffect4(() => {
|
|
1179
1294
|
if (layerStates) {
|
|
1180
1295
|
setEffectiveStates(layerStates);
|
|
1181
1296
|
}
|
|
1182
1297
|
}, [layerStates]);
|
|
1183
|
-
|
|
1298
|
+
useEffect4(() => {
|
|
1184
1299
|
if (layerStates) {
|
|
1185
1300
|
return;
|
|
1186
1301
|
}
|
|
@@ -1193,11 +1308,11 @@ var ZenitMap = forwardRef(({
|
|
|
1193
1308
|
setEffectiveStates(next);
|
|
1194
1309
|
onLayerStateChange?.(next);
|
|
1195
1310
|
}, [baseStates, controlOverrides, layerStates, mapOverrides, onLayerStateChange, uiOverrides]);
|
|
1196
|
-
|
|
1311
|
+
useEffect4(() => {
|
|
1197
1312
|
if (!Array.isArray(layerControls) || layerControls.length > 0) return;
|
|
1198
1313
|
setUiOverrides([]);
|
|
1199
1314
|
}, [layerControls]);
|
|
1200
|
-
|
|
1315
|
+
useEffect4(() => {
|
|
1201
1316
|
if (layerStates) {
|
|
1202
1317
|
return;
|
|
1203
1318
|
}
|
|
@@ -1217,18 +1332,13 @@ var ZenitMap = forwardRef(({
|
|
|
1217
1332
|
return [...filtered, nextEntry];
|
|
1218
1333
|
});
|
|
1219
1334
|
};
|
|
1220
|
-
const updateOpacityFromUi =
|
|
1335
|
+
const updateOpacityFromUi = useCallback2(
|
|
1221
1336
|
(layerId, uiOpacity) => {
|
|
1222
1337
|
const meta = layerMetaIndex.get(String(layerId));
|
|
1223
|
-
const
|
|
1338
|
+
const baseOpacity = clampOpacity3(uiOpacity);
|
|
1339
|
+
const effectiveOpacity = calculateZoomBasedOpacity(
|
|
1224
1340
|
currentZoom,
|
|
1225
|
-
meta?.layerType,
|
|
1226
|
-
meta?.geometryType
|
|
1227
|
-
);
|
|
1228
|
-
const baseOpacity = clampOpacity3(uiOpacity / zoomFactor);
|
|
1229
|
-
const effectiveOpacity = getEffectiveLayerOpacity(
|
|
1230
1341
|
baseOpacity,
|
|
1231
|
-
currentZoom,
|
|
1232
1342
|
meta?.layerType,
|
|
1233
1343
|
meta?.geometryType
|
|
1234
1344
|
);
|
|
@@ -1261,7 +1371,7 @@ var ZenitMap = forwardRef(({
|
|
|
1261
1371
|
},
|
|
1262
1372
|
[currentZoom, effectiveStates, layerMetaIndex, layerStates, onLayerStateChange]
|
|
1263
1373
|
);
|
|
1264
|
-
const center =
|
|
1374
|
+
const center = useMemo2(() => {
|
|
1265
1375
|
if (initialCenter) {
|
|
1266
1376
|
return initialCenter;
|
|
1267
1377
|
}
|
|
@@ -1272,36 +1382,30 @@ var ZenitMap = forwardRef(({
|
|
|
1272
1382
|
return DEFAULT_CENTER;
|
|
1273
1383
|
}, [initialCenter, map?.settings?.center]);
|
|
1274
1384
|
const zoom = initialZoom ?? map?.settings?.zoom ?? DEFAULT_ZOOM;
|
|
1275
|
-
|
|
1385
|
+
useEffect4(() => {
|
|
1276
1386
|
setCurrentZoom(zoom);
|
|
1277
1387
|
}, [zoom]);
|
|
1278
|
-
const decoratedLayers =
|
|
1388
|
+
const decoratedLayers = useMemo2(() => {
|
|
1279
1389
|
return layers.map((layer) => ({
|
|
1280
1390
|
...layer,
|
|
1281
1391
|
effective: effectiveStates.find((state) => state.layerId === layer.mapLayer.layerId),
|
|
1282
1392
|
data: layerGeojson?.[layer.mapLayer.layerId] ?? layerGeojson?.[String(layer.mapLayer.layerId)] ?? null
|
|
1283
1393
|
}));
|
|
1284
1394
|
}, [effectiveStates, layerGeojson, layers]);
|
|
1285
|
-
const orderedLayers =
|
|
1395
|
+
const orderedLayers = useMemo2(() => {
|
|
1286
1396
|
return [...decoratedLayers].filter((layer) => layer.effective?.visible && layer.data).sort((a, b) => a.displayOrder - b.displayOrder);
|
|
1287
1397
|
}, [decoratedLayers]);
|
|
1288
|
-
const
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
const autoZoomBBox = useMemo(() => {
|
|
1294
|
-
if (explicitZoomBBox) return null;
|
|
1295
|
-
const visibleBBoxes = orderedLayers.map((layer) => computeBBoxFromGeojson(layer.data));
|
|
1296
|
-
return mergeBBoxes(visibleBBoxes);
|
|
1297
|
-
}, [explicitZoomBBox, orderedLayers]);
|
|
1298
|
-
const resolveLayerStyle = useCallback(
|
|
1398
|
+
const autoZoomGeojson = useMemo2(
|
|
1399
|
+
() => orderedLayers.map((layer) => layer.data).filter((collection) => !!collection),
|
|
1400
|
+
[orderedLayers]
|
|
1401
|
+
);
|
|
1402
|
+
const resolveLayerStyle = useCallback2(
|
|
1299
1403
|
(layerId) => {
|
|
1300
1404
|
return getStyleByLayerId(layerId, mapLayers) ?? layerStyleIndex.get(String(layerId)) ?? null;
|
|
1301
1405
|
},
|
|
1302
1406
|
[layerStyleIndex, mapLayers]
|
|
1303
1407
|
);
|
|
1304
|
-
const labelMarkers =
|
|
1408
|
+
const labelMarkers = useMemo2(() => {
|
|
1305
1409
|
const markers = [];
|
|
1306
1410
|
decoratedLayers.forEach((layerState) => {
|
|
1307
1411
|
if (!layerState.effective?.visible) return;
|
|
@@ -1311,7 +1415,14 @@ var ZenitMap = forwardRef(({
|
|
|
1311
1415
|
if (!data) return;
|
|
1312
1416
|
const resolvedStyle = resolveLayerStyle(layerState.mapLayer.layerId);
|
|
1313
1417
|
const layerColor = resolvedStyle?.fillColor ?? resolvedStyle?.color ?? "rgba(37, 99, 235, 1)";
|
|
1314
|
-
const
|
|
1418
|
+
const meta = layerMetaIndex.get(String(layerState.mapLayer.layerId));
|
|
1419
|
+
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
1420
|
+
const opacity = calculateZoomBasedOpacity(
|
|
1421
|
+
currentZoom,
|
|
1422
|
+
baseOpacity,
|
|
1423
|
+
meta?.layerType,
|
|
1424
|
+
meta?.geometryType
|
|
1425
|
+
);
|
|
1315
1426
|
data.features.forEach((feature, index) => {
|
|
1316
1427
|
const properties = feature.properties;
|
|
1317
1428
|
const value = properties?.[labelKey];
|
|
@@ -1330,8 +1441,8 @@ var ZenitMap = forwardRef(({
|
|
|
1330
1441
|
});
|
|
1331
1442
|
});
|
|
1332
1443
|
return markers;
|
|
1333
|
-
}, [decoratedLayers, labelKeyIndex, resolveLayerStyle]);
|
|
1334
|
-
const ensureLayerPanes =
|
|
1444
|
+
}, [currentZoom, decoratedLayers, labelKeyIndex, layerMetaIndex, resolveLayerStyle]);
|
|
1445
|
+
const ensureLayerPanes = useCallback2(
|
|
1335
1446
|
(targetMap, targetLayers) => {
|
|
1336
1447
|
const baseZIndex = 400;
|
|
1337
1448
|
targetLayers.forEach((layer) => {
|
|
@@ -1347,7 +1458,7 @@ var ZenitMap = forwardRef(({
|
|
|
1347
1458
|
},
|
|
1348
1459
|
[]
|
|
1349
1460
|
);
|
|
1350
|
-
const handleMapReady =
|
|
1461
|
+
const handleMapReady = useCallback2(
|
|
1351
1462
|
(instance) => {
|
|
1352
1463
|
setPanesReady(false);
|
|
1353
1464
|
setMapInstance(instance);
|
|
@@ -1355,7 +1466,7 @@ var ZenitMap = forwardRef(({
|
|
|
1355
1466
|
},
|
|
1356
1467
|
[onMapReady]
|
|
1357
1468
|
);
|
|
1358
|
-
|
|
1469
|
+
useEffect4(() => {
|
|
1359
1470
|
if (!mapInstance) {
|
|
1360
1471
|
setPanesReady(false);
|
|
1361
1472
|
return;
|
|
@@ -1375,19 +1486,19 @@ var ZenitMap = forwardRef(({
|
|
|
1375
1486
|
setPanesReady(true);
|
|
1376
1487
|
}
|
|
1377
1488
|
}, [mapInstance, orderedLayers, ensureLayerPanes]);
|
|
1378
|
-
const overlayOnEachFeature =
|
|
1489
|
+
const overlayOnEachFeature = useMemo2(() => {
|
|
1379
1490
|
return (feature, layer) => {
|
|
1380
1491
|
const layerId = getFeatureLayerId(feature) ?? void 0;
|
|
1381
1492
|
const geometryType = feature?.geometry?.type;
|
|
1382
|
-
const isPointFeature = geometryType === "Point" || geometryType === "MultiPoint" || layer instanceof
|
|
1383
|
-
const originalStyle = layer instanceof
|
|
1493
|
+
const isPointFeature = geometryType === "Point" || geometryType === "MultiPoint" || layer instanceof L4.CircleMarker;
|
|
1494
|
+
const originalStyle = layer instanceof L4.Path ? {
|
|
1384
1495
|
color: layer.options.color,
|
|
1385
1496
|
weight: layer.options.weight,
|
|
1386
1497
|
fillColor: layer.options.fillColor,
|
|
1387
1498
|
opacity: layer.options.opacity,
|
|
1388
1499
|
fillOpacity: layer.options.fillOpacity
|
|
1389
1500
|
} : null;
|
|
1390
|
-
const originalRadius = layer instanceof
|
|
1501
|
+
const originalRadius = layer instanceof L4.CircleMarker ? layer.getRadius() : null;
|
|
1391
1502
|
if (featureInfoMode === "popup") {
|
|
1392
1503
|
const content = buildFeaturePopupHtml(feature);
|
|
1393
1504
|
if (content) {
|
|
@@ -1396,11 +1507,10 @@ var ZenitMap = forwardRef(({
|
|
|
1396
1507
|
maxWidth,
|
|
1397
1508
|
minWidth,
|
|
1398
1509
|
maxHeight,
|
|
1399
|
-
className: "
|
|
1510
|
+
className: "custom-leaflet-popup",
|
|
1400
1511
|
autoPan: true,
|
|
1401
1512
|
closeButton: true,
|
|
1402
|
-
keepInView: true
|
|
1403
|
-
offset: L.point(0, -24)
|
|
1513
|
+
keepInView: true
|
|
1404
1514
|
});
|
|
1405
1515
|
}
|
|
1406
1516
|
}
|
|
@@ -1445,7 +1555,7 @@ var ZenitMap = forwardRef(({
|
|
|
1445
1555
|
onFeatureClick?.(feature, layerId);
|
|
1446
1556
|
});
|
|
1447
1557
|
layer.on("mouseover", () => {
|
|
1448
|
-
if (layer instanceof
|
|
1558
|
+
if (layer instanceof L4.Path && originalStyle) {
|
|
1449
1559
|
layer.setStyle({
|
|
1450
1560
|
...originalStyle,
|
|
1451
1561
|
weight: (originalStyle.weight ?? 2) + 1,
|
|
@@ -1453,16 +1563,16 @@ var ZenitMap = forwardRef(({
|
|
|
1453
1563
|
fillOpacity: Math.min(1, (originalStyle.fillOpacity ?? 0.8) + 0.1)
|
|
1454
1564
|
});
|
|
1455
1565
|
}
|
|
1456
|
-
if (layer instanceof
|
|
1566
|
+
if (layer instanceof L4.CircleMarker && typeof originalRadius === "number") {
|
|
1457
1567
|
layer.setRadius(originalRadius + 1);
|
|
1458
1568
|
}
|
|
1459
1569
|
onFeatureHover?.(feature, layerId);
|
|
1460
1570
|
});
|
|
1461
1571
|
layer.on("mouseout", () => {
|
|
1462
|
-
if (layer instanceof
|
|
1572
|
+
if (layer instanceof L4.Path && originalStyle) {
|
|
1463
1573
|
layer.setStyle(originalStyle);
|
|
1464
1574
|
}
|
|
1465
|
-
if (layer instanceof
|
|
1575
|
+
if (layer instanceof L4.CircleMarker && typeof originalRadius === "number") {
|
|
1466
1576
|
layer.setRadius(originalRadius);
|
|
1467
1577
|
}
|
|
1468
1578
|
});
|
|
@@ -1474,79 +1584,19 @@ var ZenitMap = forwardRef(({
|
|
|
1474
1584
|
const resolvedStyle = featureStyleOverrides ? { ...style ?? {}, ...featureStyleOverrides } : style;
|
|
1475
1585
|
const geometryType = feature?.geometry?.type;
|
|
1476
1586
|
const resolvedLayerType = layerType ?? geometryType;
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
resolvedLayerType
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
color: resolvedStyle?.color ?? resolvedStyle?.fillColor ?? "#2563eb",
|
|
1489
|
-
weight: resolvedStyle?.weight ?? 2,
|
|
1490
|
-
fillColor: resolvedStyle?.fillColor ?? resolvedStyle?.color ?? "#2563eb",
|
|
1491
|
-
opacity: strokeOpacity,
|
|
1492
|
-
fillOpacity
|
|
1587
|
+
return layerStyleToLeaflet({
|
|
1588
|
+
baseOpacity,
|
|
1589
|
+
zoom: currentZoom,
|
|
1590
|
+
layerStyle: resolvedStyle,
|
|
1591
|
+
geometryType,
|
|
1592
|
+
layerType: resolvedLayerType
|
|
1593
|
+
});
|
|
1594
|
+
};
|
|
1595
|
+
const makeStyleFnForLayer = (layerId) => {
|
|
1596
|
+
return (feature, layerType, baseOpacity) => {
|
|
1597
|
+
return buildLayerStyle(layerId, baseOpacity ?? 1, feature, layerType);
|
|
1493
1598
|
};
|
|
1494
1599
|
};
|
|
1495
|
-
const buildLabelIcon = useCallback((label, opacity, color) => {
|
|
1496
|
-
const size = 60;
|
|
1497
|
-
const innerSize = 44;
|
|
1498
|
-
const textStyles = getLabelTextStyles(color);
|
|
1499
|
-
const safeLabel = escapeHtml(label);
|
|
1500
|
-
const clampedOpacity = Math.min(1, Math.max(0.92, opacity));
|
|
1501
|
-
const innerBackground = withAlpha(color, 0.9);
|
|
1502
|
-
return L.divIcon({
|
|
1503
|
-
className: "zenit-label-marker",
|
|
1504
|
-
iconSize: [size, size],
|
|
1505
|
-
iconAnchor: [size / 2, size / 2],
|
|
1506
|
-
html: `
|
|
1507
|
-
<div
|
|
1508
|
-
title="${safeLabel}"
|
|
1509
|
-
style="
|
|
1510
|
-
width:${size}px;
|
|
1511
|
-
height:${size}px;
|
|
1512
|
-
border-radius:9999px;
|
|
1513
|
-
background:rgba(255, 255, 255, 0.95);
|
|
1514
|
-
border:3px solid rgba(255, 255, 255, 1);
|
|
1515
|
-
display:flex;
|
|
1516
|
-
align-items:center;
|
|
1517
|
-
justify-content:center;
|
|
1518
|
-
opacity:${clampedOpacity};
|
|
1519
|
-
box-shadow:0 2px 6px rgba(0, 0, 0, 0.25);
|
|
1520
|
-
pointer-events:none;
|
|
1521
|
-
"
|
|
1522
|
-
>
|
|
1523
|
-
<div
|
|
1524
|
-
style="
|
|
1525
|
-
width:${innerSize}px;
|
|
1526
|
-
height:${innerSize}px;
|
|
1527
|
-
border-radius:9999px;
|
|
1528
|
-
background:${innerBackground};
|
|
1529
|
-
display:flex;
|
|
1530
|
-
align-items:center;
|
|
1531
|
-
justify-content:center;
|
|
1532
|
-
box-shadow:inset 0 0 0 1px rgba(15, 23, 42, 0.12);
|
|
1533
|
-
"
|
|
1534
|
-
>
|
|
1535
|
-
<span
|
|
1536
|
-
style="
|
|
1537
|
-
color:${textStyles.color};
|
|
1538
|
-
font-size:20px;
|
|
1539
|
-
font-weight:800;
|
|
1540
|
-
text-shadow:${textStyles.shadow};
|
|
1541
|
-
"
|
|
1542
|
-
>
|
|
1543
|
-
${safeLabel}
|
|
1544
|
-
</span>
|
|
1545
|
-
</div>
|
|
1546
|
-
</div>
|
|
1547
|
-
`
|
|
1548
|
-
});
|
|
1549
|
-
}, []);
|
|
1550
1600
|
useImperativeHandle(ref, () => ({
|
|
1551
1601
|
setLayerOpacity: (layerId, opacity) => {
|
|
1552
1602
|
upsertUiOverride(layerId, { overrideOpacity: opacity });
|
|
@@ -1597,10 +1647,10 @@ var ZenitMap = forwardRef(({
|
|
|
1597
1647
|
getMapInstance: () => mapInstance
|
|
1598
1648
|
}), [effectiveStates, mapInstance]);
|
|
1599
1649
|
if (loadingMap) {
|
|
1600
|
-
return /* @__PURE__ */
|
|
1650
|
+
return /* @__PURE__ */ jsx3("div", { style: { padding: 16, height, width }, children: "Cargando mapa..." });
|
|
1601
1651
|
}
|
|
1602
1652
|
if (mapError) {
|
|
1603
|
-
return /* @__PURE__ */
|
|
1653
|
+
return /* @__PURE__ */ jsxs3("div", { style: { padding: 16, height, width, color: "red" }, children: [
|
|
1604
1654
|
"Error al cargar mapa: ",
|
|
1605
1655
|
mapError
|
|
1606
1656
|
] });
|
|
@@ -1612,7 +1662,7 @@ var ZenitMap = forwardRef(({
|
|
|
1612
1662
|
setCurrentZoom(zoomValue);
|
|
1613
1663
|
onZoomChange?.(zoomValue);
|
|
1614
1664
|
};
|
|
1615
|
-
return /* @__PURE__ */
|
|
1665
|
+
return /* @__PURE__ */ jsxs3(
|
|
1616
1666
|
"div",
|
|
1617
1667
|
{
|
|
1618
1668
|
style: {
|
|
@@ -1625,12 +1675,12 @@ var ZenitMap = forwardRef(({
|
|
|
1625
1675
|
boxSizing: "border-box"
|
|
1626
1676
|
},
|
|
1627
1677
|
children: [
|
|
1628
|
-
/* @__PURE__ */
|
|
1678
|
+
/* @__PURE__ */ jsx3(
|
|
1629
1679
|
"div",
|
|
1630
1680
|
{
|
|
1631
1681
|
className: `zenit-map-shell${isPopupOpen ? " popup-open" : ""}`,
|
|
1632
1682
|
style: { flex: 1, position: "relative" },
|
|
1633
|
-
children: /* @__PURE__ */
|
|
1683
|
+
children: /* @__PURE__ */ jsxs3(
|
|
1634
1684
|
MapContainer,
|
|
1635
1685
|
{
|
|
1636
1686
|
center,
|
|
@@ -1639,57 +1689,68 @@ var ZenitMap = forwardRef(({
|
|
|
1639
1689
|
scrollWheelZoom: true,
|
|
1640
1690
|
zoomControl: false,
|
|
1641
1691
|
children: [
|
|
1642
|
-
/* @__PURE__ */
|
|
1692
|
+
/* @__PURE__ */ jsx3(
|
|
1643
1693
|
TileLayer,
|
|
1644
1694
|
{
|
|
1645
1695
|
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
1646
1696
|
attribution: "\xA9 OpenStreetMap contributors"
|
|
1647
1697
|
}
|
|
1648
1698
|
),
|
|
1649
|
-
/* @__PURE__ */
|
|
1650
|
-
/* @__PURE__ */
|
|
1651
|
-
/* @__PURE__ */
|
|
1652
|
-
|
|
1653
|
-
|
|
1699
|
+
/* @__PURE__ */ jsx3(ZoomControl, { position: "topright" }),
|
|
1700
|
+
/* @__PURE__ */ jsx3(MapInstanceBridge, { onReady: handleMapReady }),
|
|
1701
|
+
/* @__PURE__ */ jsx3(
|
|
1702
|
+
BBoxZoomHandler,
|
|
1703
|
+
{
|
|
1704
|
+
bbox: zoomToBbox ?? void 0,
|
|
1705
|
+
geojson: zoomToGeojson ?? void 0,
|
|
1706
|
+
autoGeojson: autoZoomGeojson
|
|
1707
|
+
}
|
|
1708
|
+
),
|
|
1709
|
+
/* @__PURE__ */ jsx3(ZoomBasedOpacityHandler, { onZoomChange: handleZoomChange }),
|
|
1710
|
+
/* @__PURE__ */ jsx3(LocationControl, {}),
|
|
1654
1711
|
orderedLayers.map((layerState) => {
|
|
1655
1712
|
const baseOpacity = layerState.effective?.baseOpacity ?? layerState.effective?.opacity ?? 1;
|
|
1656
1713
|
const fillPaneName = `zenit-layer-${layerState.mapLayer.layerId}-fill`;
|
|
1657
1714
|
const pointsPaneName = `zenit-layer-${layerState.mapLayer.layerId}-points`;
|
|
1658
1715
|
const layerType = layerState.layer?.layerType ?? layerState.mapLayer.layerType ?? void 0;
|
|
1659
|
-
const
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
const pointsData = pointFeatures.length > 0 ? buildFeatureCollection(pointFeatures) : null;
|
|
1664
|
-
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
1665
|
-
fillData && /* @__PURE__ */ jsx(
|
|
1666
|
-
GeoJSON,
|
|
1667
|
-
{
|
|
1668
|
-
data: fillData,
|
|
1669
|
-
pane: panesReady && mapInstance?.getPane(fillPaneName) ? fillPaneName : void 0,
|
|
1670
|
-
style: (feature) => buildLayerStyle(layerState.mapLayer.layerId, baseOpacity, feature, layerType),
|
|
1671
|
-
onEachFeature: overlayOnEachFeature
|
|
1672
|
-
}
|
|
1673
|
-
),
|
|
1674
|
-
pointsData && /* @__PURE__ */ jsx(
|
|
1675
|
-
GeoJSON,
|
|
1716
|
+
const labelKey = labelKeyIndex.get(String(layerState.mapLayer.layerId));
|
|
1717
|
+
return /* @__PURE__ */ jsxs3(React3.Fragment, { children: [
|
|
1718
|
+
layerState.data && /* @__PURE__ */ jsx3(
|
|
1719
|
+
LayerGeoJson,
|
|
1676
1720
|
{
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1721
|
+
layerId: layerState.mapLayer.layerId,
|
|
1722
|
+
data: layerState.data,
|
|
1723
|
+
baseOpacity,
|
|
1724
|
+
isMobile,
|
|
1725
|
+
panesReady,
|
|
1726
|
+
mapInstance,
|
|
1727
|
+
fillPaneName,
|
|
1728
|
+
pointsPaneName,
|
|
1729
|
+
layerType,
|
|
1730
|
+
styleFn: makeStyleFnForLayer(layerState.mapLayer.layerId),
|
|
1731
|
+
onEachFeature: overlayOnEachFeature,
|
|
1732
|
+
onPolygonLabel: labelKey ? (feature, layer) => {
|
|
1733
|
+
const geometryType = feature?.geometry?.type;
|
|
1734
|
+
if (geometryType !== "Polygon" && geometryType !== "MultiPolygon") return;
|
|
1735
|
+
const properties = feature?.properties;
|
|
1736
|
+
const value = properties?.[labelKey];
|
|
1737
|
+
if (!value || !layer.bindTooltip) return;
|
|
1738
|
+
layer.bindTooltip(String(value), {
|
|
1739
|
+
sticky: true,
|
|
1740
|
+
direction: "center",
|
|
1741
|
+
opacity: 0.9,
|
|
1742
|
+
className: "polygon-label-tooltip"
|
|
1743
|
+
});
|
|
1744
|
+
} : void 0
|
|
1684
1745
|
}
|
|
1685
1746
|
),
|
|
1686
1747
|
panesReady && mapInstance?.getPane(LABELS_PANE_NAME) ? labelMarkers.filter(
|
|
1687
1748
|
(marker) => String(marker.layerId) === String(layerState.mapLayer.layerId)
|
|
1688
|
-
).map((marker) => /* @__PURE__ */
|
|
1689
|
-
|
|
1749
|
+
).map((marker) => /* @__PURE__ */ jsx3(
|
|
1750
|
+
Marker2,
|
|
1690
1751
|
{
|
|
1691
1752
|
position: marker.position,
|
|
1692
|
-
icon:
|
|
1753
|
+
icon: createCustomIcon(marker.label, marker.opacity, marker.color),
|
|
1693
1754
|
interactive: false,
|
|
1694
1755
|
pane: LABELS_PANE_NAME
|
|
1695
1756
|
},
|
|
@@ -1697,14 +1758,20 @@ var ZenitMap = forwardRef(({
|
|
|
1697
1758
|
)) : null
|
|
1698
1759
|
] }, layerState.mapLayer.layerId.toString());
|
|
1699
1760
|
}),
|
|
1700
|
-
overlayGeojson && /* @__PURE__ */
|
|
1701
|
-
|
|
1761
|
+
overlayGeojson && /* @__PURE__ */ jsx3(
|
|
1762
|
+
LayerGeoJson,
|
|
1702
1763
|
{
|
|
1764
|
+
layerId: "overlay-geojson",
|
|
1703
1765
|
data: overlayGeojson,
|
|
1704
|
-
|
|
1766
|
+
baseOpacity: 1,
|
|
1767
|
+
isMobile,
|
|
1768
|
+
panesReady,
|
|
1769
|
+
mapInstance,
|
|
1770
|
+
fillPaneName: "zenit-overlay-fill",
|
|
1771
|
+
pointsPaneName: "zenit-overlay-points",
|
|
1772
|
+
styleFn: overlayStyleFn,
|
|
1705
1773
|
onEachFeature: overlayOnEachFeature
|
|
1706
|
-
}
|
|
1707
|
-
"zenit-overlay-geojson"
|
|
1774
|
+
}
|
|
1708
1775
|
)
|
|
1709
1776
|
]
|
|
1710
1777
|
},
|
|
@@ -1712,7 +1779,7 @@ var ZenitMap = forwardRef(({
|
|
|
1712
1779
|
)
|
|
1713
1780
|
}
|
|
1714
1781
|
),
|
|
1715
|
-
showLayerPanel && decoratedLayers.length > 0 && /* @__PURE__ */
|
|
1782
|
+
showLayerPanel && decoratedLayers.length > 0 && /* @__PURE__ */ jsxs3(
|
|
1716
1783
|
"div",
|
|
1717
1784
|
{
|
|
1718
1785
|
style: {
|
|
@@ -1725,7 +1792,7 @@ var ZenitMap = forwardRef(({
|
|
|
1725
1792
|
overflowY: "auto"
|
|
1726
1793
|
},
|
|
1727
1794
|
children: [
|
|
1728
|
-
overlayGeojson && /* @__PURE__ */
|
|
1795
|
+
overlayGeojson && /* @__PURE__ */ jsxs3(
|
|
1729
1796
|
"div",
|
|
1730
1797
|
{
|
|
1731
1798
|
style: {
|
|
@@ -1737,8 +1804,8 @@ var ZenitMap = forwardRef(({
|
|
|
1737
1804
|
marginBottom: 12
|
|
1738
1805
|
},
|
|
1739
1806
|
children: [
|
|
1740
|
-
/* @__PURE__ */
|
|
1741
|
-
/* @__PURE__ */
|
|
1807
|
+
/* @__PURE__ */ jsx3("div", { style: { fontWeight: 600, marginBottom: 4 }, children: "Overlay activo" }),
|
|
1808
|
+
/* @__PURE__ */ jsxs3("div", { style: { fontSize: 13 }, children: [
|
|
1742
1809
|
"GeoJSON externo con ",
|
|
1743
1810
|
(overlayGeojson.features?.length ?? 0).toLocaleString(),
|
|
1744
1811
|
" elementos."
|
|
@@ -1746,14 +1813,14 @@ var ZenitMap = forwardRef(({
|
|
|
1746
1813
|
]
|
|
1747
1814
|
}
|
|
1748
1815
|
),
|
|
1749
|
-
/* @__PURE__ */
|
|
1750
|
-
decoratedLayers.map((layerState) => /* @__PURE__ */
|
|
1816
|
+
/* @__PURE__ */ jsx3("div", { style: { fontWeight: 600, marginBottom: 12 }, children: "Capas" }),
|
|
1817
|
+
decoratedLayers.map((layerState) => /* @__PURE__ */ jsxs3(
|
|
1751
1818
|
"div",
|
|
1752
1819
|
{
|
|
1753
1820
|
style: { borderBottom: "1px solid #e5e7eb", paddingBottom: 10, marginBottom: 10 },
|
|
1754
1821
|
children: [
|
|
1755
|
-
/* @__PURE__ */
|
|
1756
|
-
/* @__PURE__ */
|
|
1822
|
+
/* @__PURE__ */ jsxs3("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
|
1823
|
+
/* @__PURE__ */ jsx3(
|
|
1757
1824
|
"input",
|
|
1758
1825
|
{
|
|
1759
1826
|
type: "checkbox",
|
|
@@ -1764,17 +1831,17 @@ var ZenitMap = forwardRef(({
|
|
|
1764
1831
|
}
|
|
1765
1832
|
}
|
|
1766
1833
|
),
|
|
1767
|
-
/* @__PURE__ */
|
|
1834
|
+
/* @__PURE__ */ jsx3("span", { children: layerState.layer?.name ?? `Capa ${layerState.mapLayer.layerId}` })
|
|
1768
1835
|
] }),
|
|
1769
|
-
/* @__PURE__ */
|
|
1770
|
-
/* @__PURE__ */
|
|
1771
|
-
/* @__PURE__ */
|
|
1772
|
-
/* @__PURE__ */
|
|
1836
|
+
/* @__PURE__ */ jsxs3("div", { style: { marginTop: 8 }, children: [
|
|
1837
|
+
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 4 }, children: [
|
|
1838
|
+
/* @__PURE__ */ jsx3("span", { style: { color: "#4a5568" }, children: "Opacidad" }),
|
|
1839
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1773
1840
|
Math.round((layerState.effective?.opacity ?? 1) * 100),
|
|
1774
1841
|
"%"
|
|
1775
1842
|
] })
|
|
1776
1843
|
] }),
|
|
1777
|
-
/* @__PURE__ */
|
|
1844
|
+
/* @__PURE__ */ jsx3(
|
|
1778
1845
|
"input",
|
|
1779
1846
|
{
|
|
1780
1847
|
type: "range",
|
|
@@ -1804,13 +1871,13 @@ var ZenitMap = forwardRef(({
|
|
|
1804
1871
|
ZenitMap.displayName = "ZenitMap";
|
|
1805
1872
|
|
|
1806
1873
|
// src/react/ZenitLayerManager.tsx
|
|
1807
|
-
import
|
|
1874
|
+
import React4, { useEffect as useEffect5, useMemo as useMemo3, useRef as useRef5, useState as useState3 } from "react";
|
|
1808
1875
|
|
|
1809
1876
|
// src/react/icons.tsx
|
|
1810
1877
|
import { Eye, EyeOff, ChevronLeft, ChevronRight, Layers, Upload, X, ZoomIn } from "lucide-react";
|
|
1811
1878
|
|
|
1812
1879
|
// src/react/ZenitLayerManager.tsx
|
|
1813
|
-
import { jsx as
|
|
1880
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1814
1881
|
var FLOAT_TOLERANCE = 1e-3;
|
|
1815
1882
|
function areEffectiveStatesEqual(a, b) {
|
|
1816
1883
|
if (a.length !== b.length) return false;
|
|
@@ -1850,15 +1917,15 @@ var ZenitLayerManager = ({
|
|
|
1850
1917
|
layerFeatureCounts,
|
|
1851
1918
|
mapLayers
|
|
1852
1919
|
}) => {
|
|
1853
|
-
const [map, setMap] =
|
|
1854
|
-
const [loadingMap, setLoadingMap] =
|
|
1855
|
-
const [mapError, setMapError] =
|
|
1856
|
-
const [layers, setLayers] =
|
|
1857
|
-
const [activeTab, setActiveTab] =
|
|
1858
|
-
const [panelVisible, setPanelVisible] =
|
|
1859
|
-
const lastEmittedStatesRef =
|
|
1920
|
+
const [map, setMap] = useState3(null);
|
|
1921
|
+
const [loadingMap, setLoadingMap] = useState3(false);
|
|
1922
|
+
const [mapError, setMapError] = useState3(null);
|
|
1923
|
+
const [layers, setLayers] = useState3([]);
|
|
1924
|
+
const [activeTab, setActiveTab] = useState3("layers");
|
|
1925
|
+
const [panelVisible, setPanelVisible] = useState3(true);
|
|
1926
|
+
const lastEmittedStatesRef = useRef5(null);
|
|
1860
1927
|
const isControlled = Array.isArray(layerStates) && typeof onLayerStatesChange === "function";
|
|
1861
|
-
const baseStates =
|
|
1928
|
+
const baseStates = useMemo3(
|
|
1862
1929
|
() => initLayerStates(
|
|
1863
1930
|
layers.map((entry) => ({
|
|
1864
1931
|
...entry.mapLayer,
|
|
@@ -1869,7 +1936,7 @@ var ZenitLayerManager = ({
|
|
|
1869
1936
|
),
|
|
1870
1937
|
[layers]
|
|
1871
1938
|
);
|
|
1872
|
-
const overrideStates =
|
|
1939
|
+
const overrideStates = useMemo3(
|
|
1873
1940
|
() => layers.map(
|
|
1874
1941
|
(entry) => ({
|
|
1875
1942
|
layerId: entry.mapLayer.layerId,
|
|
@@ -1879,11 +1946,11 @@ var ZenitLayerManager = ({
|
|
|
1879
1946
|
),
|
|
1880
1947
|
[layers]
|
|
1881
1948
|
);
|
|
1882
|
-
const effectiveStates =
|
|
1949
|
+
const effectiveStates = useMemo3(
|
|
1883
1950
|
() => layerStates ?? applyLayerOverrides(baseStates, overrideStates),
|
|
1884
1951
|
[baseStates, layerStates, overrideStates]
|
|
1885
1952
|
);
|
|
1886
|
-
const layerMetaIndex =
|
|
1953
|
+
const layerMetaIndex = useMemo3(() => {
|
|
1887
1954
|
const index = /* @__PURE__ */ new Map();
|
|
1888
1955
|
mapLayers?.forEach((entry) => {
|
|
1889
1956
|
const key = String(entry.layerId);
|
|
@@ -1897,7 +1964,7 @@ var ZenitLayerManager = ({
|
|
|
1897
1964
|
});
|
|
1898
1965
|
return index;
|
|
1899
1966
|
}, [map, mapLayers]);
|
|
1900
|
-
const resolveUserOpacity =
|
|
1967
|
+
const resolveUserOpacity = React4.useCallback((state) => {
|
|
1901
1968
|
if (typeof state.overrideOpacity === "number") return state.overrideOpacity;
|
|
1902
1969
|
if (typeof state.overrideOpacity === "string") {
|
|
1903
1970
|
const parsed = Number.parseFloat(state.overrideOpacity);
|
|
@@ -1905,7 +1972,7 @@ var ZenitLayerManager = ({
|
|
|
1905
1972
|
}
|
|
1906
1973
|
return state.opacity ?? 1;
|
|
1907
1974
|
}, []);
|
|
1908
|
-
const resolveEffectiveOpacity =
|
|
1975
|
+
const resolveEffectiveOpacity = React4.useCallback(
|
|
1909
1976
|
(layerId, userOpacity) => {
|
|
1910
1977
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
1911
1978
|
return userOpacity;
|
|
@@ -1921,7 +1988,7 @@ var ZenitLayerManager = ({
|
|
|
1921
1988
|
},
|
|
1922
1989
|
[autoOpacityConfig, autoOpacityOnZoom, layerMetaIndex, mapZoom]
|
|
1923
1990
|
);
|
|
1924
|
-
const effectiveStatesWithZoom =
|
|
1991
|
+
const effectiveStatesWithZoom = useMemo3(() => {
|
|
1925
1992
|
if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
|
|
1926
1993
|
return effectiveStates;
|
|
1927
1994
|
}
|
|
@@ -1935,7 +2002,7 @@ var ZenitLayerManager = ({
|
|
|
1935
2002
|
};
|
|
1936
2003
|
});
|
|
1937
2004
|
}, [autoOpacityOnZoom, effectiveStates, mapZoom, resolveEffectiveOpacity, resolveUserOpacity]);
|
|
1938
|
-
|
|
2005
|
+
useEffect5(() => {
|
|
1939
2006
|
let cancelled = false;
|
|
1940
2007
|
setLoadingMap(true);
|
|
1941
2008
|
setMapError(null);
|
|
@@ -1967,12 +2034,12 @@ var ZenitLayerManager = ({
|
|
|
1967
2034
|
cancelled = true;
|
|
1968
2035
|
};
|
|
1969
2036
|
}, [client.maps, mapId]);
|
|
1970
|
-
|
|
2037
|
+
useEffect5(() => {
|
|
1971
2038
|
if (!showUploadTab && activeTab === "upload") {
|
|
1972
2039
|
setActiveTab("layers");
|
|
1973
2040
|
}
|
|
1974
2041
|
}, [activeTab, showUploadTab]);
|
|
1975
|
-
|
|
2042
|
+
useEffect5(() => {
|
|
1976
2043
|
if (isControlled) return;
|
|
1977
2044
|
if (!onLayerStatesChange) return;
|
|
1978
2045
|
const emitStates = autoOpacityOnZoom && typeof mapZoom === "number" ? effectiveStatesWithZoom : effectiveStates;
|
|
@@ -1990,7 +2057,7 @@ var ZenitLayerManager = ({
|
|
|
1990
2057
|
mapZoom,
|
|
1991
2058
|
onLayerStatesChange
|
|
1992
2059
|
]);
|
|
1993
|
-
const updateLayerVisible =
|
|
2060
|
+
const updateLayerVisible = React4.useCallback(
|
|
1994
2061
|
(layerId, visible) => {
|
|
1995
2062
|
if (!onLayerStatesChange) return;
|
|
1996
2063
|
const next = effectiveStates.map(
|
|
@@ -2000,7 +2067,7 @@ var ZenitLayerManager = ({
|
|
|
2000
2067
|
},
|
|
2001
2068
|
[effectiveStates, onLayerStatesChange]
|
|
2002
2069
|
);
|
|
2003
|
-
const updateLayerOpacity =
|
|
2070
|
+
const updateLayerOpacity = React4.useCallback(
|
|
2004
2071
|
(layerId, opacity) => {
|
|
2005
2072
|
if (!onLayerStatesChange) return;
|
|
2006
2073
|
const adjustedOpacity = resolveEffectiveOpacity(layerId, opacity);
|
|
@@ -2011,7 +2078,7 @@ var ZenitLayerManager = ({
|
|
|
2011
2078
|
},
|
|
2012
2079
|
[effectiveStates, onLayerStatesChange, resolveEffectiveOpacity]
|
|
2013
2080
|
);
|
|
2014
|
-
const resolveFeatureCount =
|
|
2081
|
+
const resolveFeatureCount = React4.useCallback(
|
|
2015
2082
|
(layerId, layer) => {
|
|
2016
2083
|
const resolvedFeatureCount = layerFeatureCounts?.[layerId] ?? layerFeatureCounts?.[String(layerId)];
|
|
2017
2084
|
if (typeof resolvedFeatureCount === "number") return resolvedFeatureCount;
|
|
@@ -2020,7 +2087,7 @@ var ZenitLayerManager = ({
|
|
|
2020
2087
|
},
|
|
2021
2088
|
[layerFeatureCounts]
|
|
2022
2089
|
);
|
|
2023
|
-
const decoratedLayers =
|
|
2090
|
+
const decoratedLayers = useMemo3(() => {
|
|
2024
2091
|
return layers.map((entry) => ({
|
|
2025
2092
|
...entry,
|
|
2026
2093
|
effective: effectiveStates.find((state) => state.layerId === entry.mapLayer.layerId),
|
|
@@ -2049,7 +2116,7 @@ var ZenitLayerManager = ({
|
|
|
2049
2116
|
return String(a.mapLayer.layerId).localeCompare(String(b.mapLayer.layerId));
|
|
2050
2117
|
});
|
|
2051
2118
|
}, [effectiveStates, layers, resolveFeatureCount]);
|
|
2052
|
-
const resolveLayerStyle =
|
|
2119
|
+
const resolveLayerStyle = React4.useCallback(
|
|
2053
2120
|
(layerId) => {
|
|
2054
2121
|
const layerKey = String(layerId);
|
|
2055
2122
|
const fromProp = mapLayers?.find((entry) => String(entry.layerId) === layerKey)?.style;
|
|
@@ -2079,10 +2146,10 @@ var ZenitLayerManager = ({
|
|
|
2079
2146
|
...height ? { height } : {}
|
|
2080
2147
|
};
|
|
2081
2148
|
if (loadingMap) {
|
|
2082
|
-
return /* @__PURE__ */
|
|
2149
|
+
return /* @__PURE__ */ jsx4("div", { className, style: panelStyle, children: "Cargando capas\u2026" });
|
|
2083
2150
|
}
|
|
2084
2151
|
if (mapError) {
|
|
2085
|
-
return /* @__PURE__ */
|
|
2152
|
+
return /* @__PURE__ */ jsxs4("div", { className, style: { ...panelStyle, color: "#c53030" }, children: [
|
|
2086
2153
|
"Error al cargar mapa: ",
|
|
2087
2154
|
mapError
|
|
2088
2155
|
] });
|
|
@@ -2100,7 +2167,7 @@ var ZenitLayerManager = ({
|
|
|
2100
2167
|
boxShadow: "0 1px 0 rgba(148, 163, 184, 0.25)"
|
|
2101
2168
|
};
|
|
2102
2169
|
const renderLayerCards = () => {
|
|
2103
|
-
return /* @__PURE__ */
|
|
2170
|
+
return /* @__PURE__ */ jsx4("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: decoratedLayers.map((layerState) => {
|
|
2104
2171
|
const layerId = layerState.mapLayer.layerId;
|
|
2105
2172
|
const layerName = layerState.layerName ?? `Capa ${layerId}`;
|
|
2106
2173
|
const visible = layerState.effective?.visible ?? false;
|
|
@@ -2110,7 +2177,7 @@ var ZenitLayerManager = ({
|
|
|
2110
2177
|
const muted = !visible;
|
|
2111
2178
|
const opacityPercent = Math.round(userOpacity * 100);
|
|
2112
2179
|
const sliderBackground = `linear-gradient(to right, ${layerColor} 0%, ${layerColor} ${opacityPercent}%, #e5e7eb ${opacityPercent}%, #e5e7eb 100%)`;
|
|
2113
|
-
return /* @__PURE__ */
|
|
2180
|
+
return /* @__PURE__ */ jsxs4(
|
|
2114
2181
|
"div",
|
|
2115
2182
|
{
|
|
2116
2183
|
className: `zlm-card${muted ? " is-muted" : ""}`,
|
|
@@ -2125,9 +2192,9 @@ var ZenitLayerManager = ({
|
|
|
2125
2192
|
width: "100%"
|
|
2126
2193
|
},
|
|
2127
2194
|
children: [
|
|
2128
|
-
/* @__PURE__ */
|
|
2129
|
-
/* @__PURE__ */
|
|
2130
|
-
/* @__PURE__ */
|
|
2195
|
+
/* @__PURE__ */ jsxs4("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
|
|
2196
|
+
/* @__PURE__ */ jsxs4("div", { style: { display: "flex", gap: 10, alignItems: "flex-start", minWidth: 0, flex: 1 }, children: [
|
|
2197
|
+
/* @__PURE__ */ jsx4(
|
|
2131
2198
|
"div",
|
|
2132
2199
|
{
|
|
2133
2200
|
style: {
|
|
@@ -2142,7 +2209,7 @@ var ZenitLayerManager = ({
|
|
|
2142
2209
|
title: "Color de la capa"
|
|
2143
2210
|
}
|
|
2144
2211
|
),
|
|
2145
|
-
showLayerVisibilityIcon && /* @__PURE__ */
|
|
2212
|
+
showLayerVisibilityIcon && /* @__PURE__ */ jsx4(
|
|
2146
2213
|
"button",
|
|
2147
2214
|
{
|
|
2148
2215
|
type: "button",
|
|
@@ -2153,11 +2220,11 @@ var ZenitLayerManager = ({
|
|
|
2153
2220
|
)
|
|
2154
2221
|
),
|
|
2155
2222
|
"aria-label": visible ? "Ocultar capa" : "Mostrar capa",
|
|
2156
|
-
children: visible ? /* @__PURE__ */
|
|
2223
|
+
children: visible ? /* @__PURE__ */ jsx4(Eye, { size: 16 }) : /* @__PURE__ */ jsx4(EyeOff, { size: 16 })
|
|
2157
2224
|
}
|
|
2158
2225
|
),
|
|
2159
|
-
/* @__PURE__ */
|
|
2160
|
-
/* @__PURE__ */
|
|
2226
|
+
/* @__PURE__ */ jsxs4("div", { style: { minWidth: 0, flex: 1 }, children: [
|
|
2227
|
+
/* @__PURE__ */ jsx4(
|
|
2161
2228
|
"div",
|
|
2162
2229
|
{
|
|
2163
2230
|
className: "zlm-layer-name",
|
|
@@ -2175,26 +2242,26 @@ var ZenitLayerManager = ({
|
|
|
2175
2242
|
children: layerName
|
|
2176
2243
|
}
|
|
2177
2244
|
),
|
|
2178
|
-
/* @__PURE__ */
|
|
2245
|
+
/* @__PURE__ */ jsxs4("div", { style: { color: muted ? "#94a3b8" : "#64748b", fontSize: 12 }, children: [
|
|
2179
2246
|
"ID ",
|
|
2180
2247
|
layerId
|
|
2181
2248
|
] })
|
|
2182
2249
|
] })
|
|
2183
2250
|
] }),
|
|
2184
|
-
/* @__PURE__ */
|
|
2251
|
+
/* @__PURE__ */ jsx4("div", { style: { display: "flex", alignItems: "flex-start", gap: 6, flexShrink: 0 }, children: typeof featureCount === "number" && /* @__PURE__ */ jsxs4("span", { className: "zlm-badge", children: [
|
|
2185
2252
|
featureCount.toLocaleString(),
|
|
2186
2253
|
" features"
|
|
2187
2254
|
] }) })
|
|
2188
2255
|
] }),
|
|
2189
|
-
/* @__PURE__ */
|
|
2190
|
-
/* @__PURE__ */
|
|
2191
|
-
/* @__PURE__ */
|
|
2192
|
-
/* @__PURE__ */
|
|
2256
|
+
/* @__PURE__ */ jsx4("div", { style: { display: "flex", gap: 10, alignItems: "center" }, children: /* @__PURE__ */ jsxs4("div", { style: { flex: 1 }, children: [
|
|
2257
|
+
/* @__PURE__ */ jsxs4("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 6, color: "#64748b", fontSize: 12 }, children: [
|
|
2258
|
+
/* @__PURE__ */ jsx4("span", { children: "Opacidad" }),
|
|
2259
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
2193
2260
|
opacityPercent,
|
|
2194
2261
|
"%"
|
|
2195
2262
|
] })
|
|
2196
2263
|
] }),
|
|
2197
|
-
/* @__PURE__ */
|
|
2264
|
+
/* @__PURE__ */ jsx4(
|
|
2198
2265
|
"input",
|
|
2199
2266
|
{
|
|
2200
2267
|
className: "zlm-range",
|
|
@@ -2232,8 +2299,8 @@ var ZenitLayerManager = ({
|
|
|
2232
2299
|
);
|
|
2233
2300
|
}) });
|
|
2234
2301
|
};
|
|
2235
|
-
return /* @__PURE__ */
|
|
2236
|
-
/* @__PURE__ */
|
|
2302
|
+
return /* @__PURE__ */ jsxs4("div", { className: ["zenit-layer-manager", className].filter(Boolean).join(" "), style: panelStyle, children: [
|
|
2303
|
+
/* @__PURE__ */ jsx4("style", { children: `
|
|
2237
2304
|
.zenit-layer-manager .zlm-card {
|
|
2238
2305
|
transition: box-shadow 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
|
|
2239
2306
|
box-shadow: 0 6px 16px rgba(15, 23, 42, 0.08);
|
|
@@ -2328,16 +2395,16 @@ var ZenitLayerManager = ({
|
|
|
2328
2395
|
outline-offset: 2px;
|
|
2329
2396
|
}
|
|
2330
2397
|
` }),
|
|
2331
|
-
/* @__PURE__ */
|
|
2332
|
-
/* @__PURE__ */
|
|
2333
|
-
/* @__PURE__ */
|
|
2334
|
-
/* @__PURE__ */
|
|
2335
|
-
/* @__PURE__ */
|
|
2398
|
+
/* @__PURE__ */ jsxs4("div", { style: headerStyle, children: [
|
|
2399
|
+
/* @__PURE__ */ jsxs4("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
|
|
2400
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
2401
|
+
/* @__PURE__ */ jsx4("div", { style: { fontWeight: 800, fontSize: 16, color: "#0f172a" }, children: "Gesti\xF3n de Capas" }),
|
|
2402
|
+
/* @__PURE__ */ jsxs4("div", { style: { color: "#64748b", fontSize: 12 }, children: [
|
|
2336
2403
|
"Mapa #",
|
|
2337
2404
|
map.id
|
|
2338
2405
|
] })
|
|
2339
2406
|
] }),
|
|
2340
|
-
/* @__PURE__ */
|
|
2407
|
+
/* @__PURE__ */ jsxs4(
|
|
2341
2408
|
"button",
|
|
2342
2409
|
{
|
|
2343
2410
|
type: "button",
|
|
@@ -2345,13 +2412,13 @@ var ZenitLayerManager = ({
|
|
|
2345
2412
|
className: "zlm-panel-toggle",
|
|
2346
2413
|
"aria-label": panelVisible ? "Ocultar panel de capas" : "Mostrar panel de capas",
|
|
2347
2414
|
children: [
|
|
2348
|
-
panelVisible ? /* @__PURE__ */
|
|
2415
|
+
panelVisible ? /* @__PURE__ */ jsx4(Eye, { size: 16 }) : /* @__PURE__ */ jsx4(EyeOff, { size: 16 }),
|
|
2349
2416
|
panelVisible ? "Ocultar" : "Mostrar"
|
|
2350
2417
|
]
|
|
2351
2418
|
}
|
|
2352
2419
|
)
|
|
2353
2420
|
] }),
|
|
2354
|
-
/* @__PURE__ */
|
|
2421
|
+
/* @__PURE__ */ jsxs4(
|
|
2355
2422
|
"div",
|
|
2356
2423
|
{
|
|
2357
2424
|
style: {
|
|
@@ -2364,26 +2431,26 @@ var ZenitLayerManager = ({
|
|
|
2364
2431
|
background: "#f1f5f9"
|
|
2365
2432
|
},
|
|
2366
2433
|
children: [
|
|
2367
|
-
/* @__PURE__ */
|
|
2434
|
+
/* @__PURE__ */ jsxs4(
|
|
2368
2435
|
"button",
|
|
2369
2436
|
{
|
|
2370
2437
|
type: "button",
|
|
2371
2438
|
className: `zlm-tab${activeTab === "layers" ? " is-active" : ""}`,
|
|
2372
2439
|
onClick: () => setActiveTab("layers"),
|
|
2373
2440
|
children: [
|
|
2374
|
-
/* @__PURE__ */
|
|
2441
|
+
/* @__PURE__ */ jsx4(Layers, { size: 16 }),
|
|
2375
2442
|
"Capas"
|
|
2376
2443
|
]
|
|
2377
2444
|
}
|
|
2378
2445
|
),
|
|
2379
|
-
showUploadTab && /* @__PURE__ */
|
|
2446
|
+
showUploadTab && /* @__PURE__ */ jsxs4(
|
|
2380
2447
|
"button",
|
|
2381
2448
|
{
|
|
2382
2449
|
type: "button",
|
|
2383
2450
|
className: `zlm-tab${activeTab === "upload" ? " is-active" : ""}`,
|
|
2384
2451
|
onClick: () => setActiveTab("upload"),
|
|
2385
2452
|
children: [
|
|
2386
|
-
/* @__PURE__ */
|
|
2453
|
+
/* @__PURE__ */ jsx4(Upload, { size: 16 }),
|
|
2387
2454
|
"Subir"
|
|
2388
2455
|
]
|
|
2389
2456
|
}
|
|
@@ -2392,15 +2459,15 @@ var ZenitLayerManager = ({
|
|
|
2392
2459
|
}
|
|
2393
2460
|
)
|
|
2394
2461
|
] }),
|
|
2395
|
-
panelVisible && /* @__PURE__ */
|
|
2462
|
+
panelVisible && /* @__PURE__ */ jsxs4("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
|
|
2396
2463
|
activeTab === "layers" && renderLayerCards(),
|
|
2397
|
-
showUploadTab && activeTab === "upload" && /* @__PURE__ */
|
|
2464
|
+
showUploadTab && activeTab === "upload" && /* @__PURE__ */ jsx4("div", { style: { color: "#475569", fontSize: 13 }, children: "Pr\xF3ximamente podr\xE1s subir capas desde este panel." })
|
|
2398
2465
|
] })
|
|
2399
2466
|
] });
|
|
2400
2467
|
};
|
|
2401
2468
|
|
|
2402
2469
|
// src/react/ZenitFeatureFilterPanel.tsx
|
|
2403
|
-
import { jsx as
|
|
2470
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2404
2471
|
var ZenitFeatureFilterPanel = ({
|
|
2405
2472
|
title = "Filtros",
|
|
2406
2473
|
description,
|
|
@@ -2408,7 +2475,7 @@ var ZenitFeatureFilterPanel = ({
|
|
|
2408
2475
|
style,
|
|
2409
2476
|
children
|
|
2410
2477
|
}) => {
|
|
2411
|
-
return /* @__PURE__ */
|
|
2478
|
+
return /* @__PURE__ */ jsxs5(
|
|
2412
2479
|
"section",
|
|
2413
2480
|
{
|
|
2414
2481
|
className,
|
|
@@ -2421,22 +2488,22 @@ var ZenitFeatureFilterPanel = ({
|
|
|
2421
2488
|
...style
|
|
2422
2489
|
},
|
|
2423
2490
|
children: [
|
|
2424
|
-
/* @__PURE__ */
|
|
2425
|
-
/* @__PURE__ */
|
|
2426
|
-
description && /* @__PURE__ */
|
|
2491
|
+
/* @__PURE__ */ jsxs5("header", { style: { marginBottom: 12 }, children: [
|
|
2492
|
+
/* @__PURE__ */ jsx5("h3", { style: { margin: 0, fontSize: 16 }, children: title }),
|
|
2493
|
+
description && /* @__PURE__ */ jsx5("p", { style: { margin: "6px 0 0", color: "#475569", fontSize: 13 }, children: description })
|
|
2427
2494
|
] }),
|
|
2428
|
-
/* @__PURE__ */
|
|
2495
|
+
/* @__PURE__ */ jsx5("div", { children })
|
|
2429
2496
|
]
|
|
2430
2497
|
}
|
|
2431
2498
|
);
|
|
2432
2499
|
};
|
|
2433
2500
|
|
|
2434
2501
|
// src/react/ai/FloatingChatBox.tsx
|
|
2435
|
-
import { useCallback as
|
|
2436
|
-
import { createPortal } from "react-dom";
|
|
2502
|
+
import { useCallback as useCallback4, useEffect as useEffect6, useMemo as useMemo4, useRef as useRef7, useState as useState5 } from "react";
|
|
2503
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
2437
2504
|
|
|
2438
2505
|
// src/react/hooks/use-chat.ts
|
|
2439
|
-
import { useCallback as
|
|
2506
|
+
import { useCallback as useCallback3, useRef as useRef6, useState as useState4 } from "react";
|
|
2440
2507
|
|
|
2441
2508
|
// src/ai/chat.service.ts
|
|
2442
2509
|
var DEFAULT_ERROR_MESSAGE = "No fue posible completar la solicitud al asistente.";
|
|
@@ -2572,9 +2639,9 @@ var createChatService = (config) => ({
|
|
|
2572
2639
|
|
|
2573
2640
|
// src/react/hooks/use-chat.ts
|
|
2574
2641
|
var useSendMessage = (config) => {
|
|
2575
|
-
const [isLoading, setIsLoading] =
|
|
2576
|
-
const [error, setError] =
|
|
2577
|
-
const send =
|
|
2642
|
+
const [isLoading, setIsLoading] = useState4(false);
|
|
2643
|
+
const [error, setError] = useState4(null);
|
|
2644
|
+
const send = useCallback3(
|
|
2578
2645
|
async (mapId, request, options) => {
|
|
2579
2646
|
setIsLoading(true);
|
|
2580
2647
|
setError(null);
|
|
@@ -2592,18 +2659,18 @@ var useSendMessage = (config) => {
|
|
|
2592
2659
|
return { sendMessage: send, isLoading, error };
|
|
2593
2660
|
};
|
|
2594
2661
|
var useSendMessageStream = (config) => {
|
|
2595
|
-
const [isStreaming, setIsStreaming] =
|
|
2596
|
-
const [streamingText, setStreamingText] =
|
|
2597
|
-
const [completeResponse, setCompleteResponse] =
|
|
2598
|
-
const [error, setError] =
|
|
2599
|
-
const requestIdRef =
|
|
2600
|
-
const reset =
|
|
2662
|
+
const [isStreaming, setIsStreaming] = useState4(false);
|
|
2663
|
+
const [streamingText, setStreamingText] = useState4("");
|
|
2664
|
+
const [completeResponse, setCompleteResponse] = useState4(null);
|
|
2665
|
+
const [error, setError] = useState4(null);
|
|
2666
|
+
const requestIdRef = useRef6(0);
|
|
2667
|
+
const reset = useCallback3(() => {
|
|
2601
2668
|
setIsStreaming(false);
|
|
2602
2669
|
setStreamingText("");
|
|
2603
2670
|
setCompleteResponse(null);
|
|
2604
2671
|
setError(null);
|
|
2605
2672
|
}, []);
|
|
2606
|
-
const send =
|
|
2673
|
+
const send = useCallback3(
|
|
2607
2674
|
async (mapId, request, options) => {
|
|
2608
2675
|
const requestId = requestIdRef.current + 1;
|
|
2609
2676
|
requestIdRef.current = requestId;
|
|
@@ -2657,7 +2724,7 @@ var useSendMessageStream = (config) => {
|
|
|
2657
2724
|
// src/react/components/MarkdownRenderer.tsx
|
|
2658
2725
|
import ReactMarkdown from "react-markdown";
|
|
2659
2726
|
import remarkGfm from "remark-gfm";
|
|
2660
|
-
import { jsx as
|
|
2727
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
2661
2728
|
function normalizeAssistantMarkdown(text) {
|
|
2662
2729
|
if (!text || typeof text !== "string") return "";
|
|
2663
2730
|
let normalized = text;
|
|
@@ -2673,28 +2740,28 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2673
2740
|
if (!normalizedContent) {
|
|
2674
2741
|
return null;
|
|
2675
2742
|
}
|
|
2676
|
-
return /* @__PURE__ */
|
|
2743
|
+
return /* @__PURE__ */ jsx6("div", { className, style: { wordBreak: "break-word" }, children: /* @__PURE__ */ jsx6(
|
|
2677
2744
|
ReactMarkdown,
|
|
2678
2745
|
{
|
|
2679
2746
|
remarkPlugins: [remarkGfm],
|
|
2680
2747
|
components: {
|
|
2681
2748
|
// Headings with proper spacing
|
|
2682
|
-
h1: ({ children, ...props }) => /* @__PURE__ */
|
|
2683
|
-
h2: ({ children, ...props }) => /* @__PURE__ */
|
|
2684
|
-
h3: ({ children, ...props }) => /* @__PURE__ */
|
|
2685
|
-
h4: ({ children, ...props }) => /* @__PURE__ */
|
|
2686
|
-
h5: ({ children, ...props }) => /* @__PURE__ */
|
|
2687
|
-
h6: ({ children, ...props }) => /* @__PURE__ */
|
|
2749
|
+
h1: ({ children, ...props }) => /* @__PURE__ */ jsx6("h1", { style: { fontSize: "1.5em", fontWeight: 700, marginTop: "1em", marginBottom: "0.5em" }, ...props, children }),
|
|
2750
|
+
h2: ({ children, ...props }) => /* @__PURE__ */ jsx6("h2", { style: { fontSize: "1.3em", fontWeight: 700, marginTop: "0.9em", marginBottom: "0.45em" }, ...props, children }),
|
|
2751
|
+
h3: ({ children, ...props }) => /* @__PURE__ */ jsx6("h3", { style: { fontSize: "1.15em", fontWeight: 600, marginTop: "0.75em", marginBottom: "0.4em" }, ...props, children }),
|
|
2752
|
+
h4: ({ children, ...props }) => /* @__PURE__ */ jsx6("h4", { style: { fontSize: "1.05em", fontWeight: 600, marginTop: "0.6em", marginBottom: "0.35em" }, ...props, children }),
|
|
2753
|
+
h5: ({ children, ...props }) => /* @__PURE__ */ jsx6("h5", { style: { fontSize: "1em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
|
|
2754
|
+
h6: ({ children, ...props }) => /* @__PURE__ */ jsx6("h6", { style: { fontSize: "0.95em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
|
|
2688
2755
|
// Paragraphs with comfortable line height
|
|
2689
|
-
p: ({ children, ...props }) => /* @__PURE__ */
|
|
2756
|
+
p: ({ children, ...props }) => /* @__PURE__ */ jsx6("p", { style: { marginTop: "0.5em", marginBottom: "0.5em", lineHeight: 1.6 }, ...props, children }),
|
|
2690
2757
|
// Lists with proper indentation
|
|
2691
|
-
ul: ({ children, ...props }) => /* @__PURE__ */
|
|
2692
|
-
ol: ({ children, ...props }) => /* @__PURE__ */
|
|
2693
|
-
li: ({ children, ...props }) => /* @__PURE__ */
|
|
2758
|
+
ul: ({ children, ...props }) => /* @__PURE__ */ jsx6("ul", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
|
|
2759
|
+
ol: ({ children, ...props }) => /* @__PURE__ */ jsx6("ol", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
|
|
2760
|
+
li: ({ children, ...props }) => /* @__PURE__ */ jsx6("li", { style: { marginTop: "0.25em", marginBottom: "0.25em" }, ...props, children }),
|
|
2694
2761
|
// Code blocks
|
|
2695
2762
|
code: ({ inline, children, ...props }) => {
|
|
2696
2763
|
if (inline) {
|
|
2697
|
-
return /* @__PURE__ */
|
|
2764
|
+
return /* @__PURE__ */ jsx6(
|
|
2698
2765
|
"code",
|
|
2699
2766
|
{
|
|
2700
2767
|
style: {
|
|
@@ -2709,7 +2776,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2709
2776
|
}
|
|
2710
2777
|
);
|
|
2711
2778
|
}
|
|
2712
|
-
return /* @__PURE__ */
|
|
2779
|
+
return /* @__PURE__ */ jsx6(
|
|
2713
2780
|
"code",
|
|
2714
2781
|
{
|
|
2715
2782
|
style: {
|
|
@@ -2729,9 +2796,9 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2729
2796
|
);
|
|
2730
2797
|
},
|
|
2731
2798
|
// Pre (code block wrapper)
|
|
2732
|
-
pre: ({ children, ...props }) => /* @__PURE__ */
|
|
2799
|
+
pre: ({ children, ...props }) => /* @__PURE__ */ jsx6("pre", { style: { margin: 0 }, ...props, children }),
|
|
2733
2800
|
// Blockquotes
|
|
2734
|
-
blockquote: ({ children, ...props }) => /* @__PURE__ */
|
|
2801
|
+
blockquote: ({ children, ...props }) => /* @__PURE__ */ jsx6(
|
|
2735
2802
|
"blockquote",
|
|
2736
2803
|
{
|
|
2737
2804
|
style: {
|
|
@@ -2747,11 +2814,11 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2747
2814
|
}
|
|
2748
2815
|
),
|
|
2749
2816
|
// Strong/bold
|
|
2750
|
-
strong: ({ children, ...props }) => /* @__PURE__ */
|
|
2817
|
+
strong: ({ children, ...props }) => /* @__PURE__ */ jsx6("strong", { style: { fontWeight: 600 }, ...props, children }),
|
|
2751
2818
|
// Emphasis/italic
|
|
2752
|
-
em: ({ children, ...props }) => /* @__PURE__ */
|
|
2819
|
+
em: ({ children, ...props }) => /* @__PURE__ */ jsx6("em", { style: { fontStyle: "italic" }, ...props, children }),
|
|
2753
2820
|
// Horizontal rule
|
|
2754
|
-
hr: (props) => /* @__PURE__ */
|
|
2821
|
+
hr: (props) => /* @__PURE__ */ jsx6(
|
|
2755
2822
|
"hr",
|
|
2756
2823
|
{
|
|
2757
2824
|
style: {
|
|
@@ -2764,7 +2831,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2764
2831
|
}
|
|
2765
2832
|
),
|
|
2766
2833
|
// Tables (GFM)
|
|
2767
|
-
table: ({ children, ...props }) => /* @__PURE__ */
|
|
2834
|
+
table: ({ children, ...props }) => /* @__PURE__ */ jsx6("div", { style: { overflowX: "auto", marginTop: "0.5em", marginBottom: "0.5em" }, children: /* @__PURE__ */ jsx6(
|
|
2768
2835
|
"table",
|
|
2769
2836
|
{
|
|
2770
2837
|
style: {
|
|
@@ -2776,7 +2843,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2776
2843
|
children
|
|
2777
2844
|
}
|
|
2778
2845
|
) }),
|
|
2779
|
-
th: ({ children, ...props }) => /* @__PURE__ */
|
|
2846
|
+
th: ({ children, ...props }) => /* @__PURE__ */ jsx6(
|
|
2780
2847
|
"th",
|
|
2781
2848
|
{
|
|
2782
2849
|
style: {
|
|
@@ -2790,7 +2857,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2790
2857
|
children
|
|
2791
2858
|
}
|
|
2792
2859
|
),
|
|
2793
|
-
td: ({ children, ...props }) => /* @__PURE__ */
|
|
2860
|
+
td: ({ children, ...props }) => /* @__PURE__ */ jsx6(
|
|
2794
2861
|
"td",
|
|
2795
2862
|
{
|
|
2796
2863
|
style: {
|
|
@@ -2808,32 +2875,32 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2808
2875
|
};
|
|
2809
2876
|
|
|
2810
2877
|
// src/react/ai/FloatingChatBox.tsx
|
|
2811
|
-
import { Fragment, jsx as
|
|
2812
|
-
var ChatIcon = () => /* @__PURE__ */
|
|
2813
|
-
var CloseIcon = () => /* @__PURE__ */
|
|
2814
|
-
/* @__PURE__ */
|
|
2815
|
-
/* @__PURE__ */
|
|
2878
|
+
import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2879
|
+
var ChatIcon = () => /* @__PURE__ */ jsx7("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx7("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
|
|
2880
|
+
var CloseIcon = () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2881
|
+
/* @__PURE__ */ jsx7("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
2882
|
+
/* @__PURE__ */ jsx7("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
2816
2883
|
] });
|
|
2817
|
-
var ExpandIcon = () => /* @__PURE__ */
|
|
2818
|
-
/* @__PURE__ */
|
|
2819
|
-
/* @__PURE__ */
|
|
2820
|
-
/* @__PURE__ */
|
|
2821
|
-
/* @__PURE__ */
|
|
2884
|
+
var ExpandIcon = () => /* @__PURE__ */ jsxs6("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2885
|
+
/* @__PURE__ */ jsx7("polyline", { points: "15 3 21 3 21 9" }),
|
|
2886
|
+
/* @__PURE__ */ jsx7("polyline", { points: "9 21 3 21 3 15" }),
|
|
2887
|
+
/* @__PURE__ */ jsx7("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
|
|
2888
|
+
/* @__PURE__ */ jsx7("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
|
|
2822
2889
|
] });
|
|
2823
|
-
var CollapseIcon = () => /* @__PURE__ */
|
|
2824
|
-
/* @__PURE__ */
|
|
2825
|
-
/* @__PURE__ */
|
|
2826
|
-
/* @__PURE__ */
|
|
2827
|
-
/* @__PURE__ */
|
|
2890
|
+
var CollapseIcon = () => /* @__PURE__ */ jsxs6("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2891
|
+
/* @__PURE__ */ jsx7("polyline", { points: "4 14 10 14 10 20" }),
|
|
2892
|
+
/* @__PURE__ */ jsx7("polyline", { points: "20 10 14 10 14 4" }),
|
|
2893
|
+
/* @__PURE__ */ jsx7("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
|
|
2894
|
+
/* @__PURE__ */ jsx7("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
|
|
2828
2895
|
] });
|
|
2829
|
-
var SendIcon = () => /* @__PURE__ */
|
|
2830
|
-
/* @__PURE__ */
|
|
2831
|
-
/* @__PURE__ */
|
|
2896
|
+
var SendIcon = () => /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2897
|
+
/* @__PURE__ */ jsx7("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
|
|
2898
|
+
/* @__PURE__ */ jsx7("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
2832
2899
|
] });
|
|
2833
|
-
var LayersIcon = () => /* @__PURE__ */
|
|
2834
|
-
/* @__PURE__ */
|
|
2835
|
-
/* @__PURE__ */
|
|
2836
|
-
/* @__PURE__ */
|
|
2900
|
+
var LayersIcon = () => /* @__PURE__ */ jsxs6("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2901
|
+
/* @__PURE__ */ jsx7("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
|
|
2902
|
+
/* @__PURE__ */ jsx7("polyline", { points: "2 17 12 22 22 17" }),
|
|
2903
|
+
/* @__PURE__ */ jsx7("polyline", { points: "2 12 12 17 22 12" })
|
|
2837
2904
|
] });
|
|
2838
2905
|
var styles = {
|
|
2839
2906
|
root: {
|
|
@@ -2842,8 +2909,8 @@ var styles = {
|
|
|
2842
2909
|
// Floating button (closed state - wide with text, open state - circular with X)
|
|
2843
2910
|
floatingButton: {
|
|
2844
2911
|
position: "fixed",
|
|
2845
|
-
bottom:
|
|
2846
|
-
right:
|
|
2912
|
+
bottom: 16,
|
|
2913
|
+
right: 16,
|
|
2847
2914
|
borderRadius: "999px",
|
|
2848
2915
|
border: "none",
|
|
2849
2916
|
cursor: "pointer",
|
|
@@ -2853,30 +2920,30 @@ var styles = {
|
|
|
2853
2920
|
display: "flex",
|
|
2854
2921
|
alignItems: "center",
|
|
2855
2922
|
justifyContent: "center",
|
|
2856
|
-
fontSize:
|
|
2923
|
+
fontSize: 14,
|
|
2857
2924
|
fontWeight: 600,
|
|
2858
2925
|
zIndex: 99999,
|
|
2859
2926
|
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
|
|
2860
2927
|
},
|
|
2861
2928
|
floatingButtonClosed: {
|
|
2862
|
-
padding: "
|
|
2929
|
+
padding: "12px 20px",
|
|
2863
2930
|
gap: 8
|
|
2864
2931
|
},
|
|
2865
2932
|
floatingButtonOpen: {
|
|
2866
|
-
width:
|
|
2867
|
-
height:
|
|
2933
|
+
width: 52,
|
|
2934
|
+
height: 52,
|
|
2868
2935
|
padding: 0
|
|
2869
2936
|
},
|
|
2870
2937
|
floatingButtonMobile: {
|
|
2871
|
-
width:
|
|
2872
|
-
height:
|
|
2938
|
+
width: 52,
|
|
2939
|
+
height: 52,
|
|
2873
2940
|
padding: 0
|
|
2874
2941
|
},
|
|
2875
2942
|
// Panel (expandable)
|
|
2876
2943
|
panel: {
|
|
2877
2944
|
position: "fixed",
|
|
2878
|
-
bottom:
|
|
2879
|
-
right:
|
|
2945
|
+
bottom: 80,
|
|
2946
|
+
right: 16,
|
|
2880
2947
|
background: "#fff",
|
|
2881
2948
|
borderRadius: 16,
|
|
2882
2949
|
boxShadow: "0 20px 60px rgba(15, 23, 42, 0.3), 0 0 0 1px rgba(15, 23, 42, 0.05)",
|
|
@@ -2887,16 +2954,16 @@ var styles = {
|
|
|
2887
2954
|
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
|
|
2888
2955
|
},
|
|
2889
2956
|
panelNormal: {
|
|
2890
|
-
width:
|
|
2891
|
-
height:
|
|
2957
|
+
width: 360,
|
|
2958
|
+
height: 520
|
|
2892
2959
|
},
|
|
2893
2960
|
panelExpanded: {
|
|
2894
|
-
width:
|
|
2895
|
-
height:
|
|
2961
|
+
width: 480,
|
|
2962
|
+
height: 640
|
|
2896
2963
|
},
|
|
2897
2964
|
// Header with green gradient
|
|
2898
2965
|
header: {
|
|
2899
|
-
padding: "16px
|
|
2966
|
+
padding: "14px 16px",
|
|
2900
2967
|
background: "linear-gradient(135deg, #10b981, #059669)",
|
|
2901
2968
|
color: "#fff",
|
|
2902
2969
|
display: "flex",
|
|
@@ -2905,7 +2972,7 @@ var styles = {
|
|
|
2905
2972
|
},
|
|
2906
2973
|
title: {
|
|
2907
2974
|
margin: 0,
|
|
2908
|
-
fontSize:
|
|
2975
|
+
fontSize: 15,
|
|
2909
2976
|
fontWeight: 600,
|
|
2910
2977
|
letterSpacing: "-0.01em"
|
|
2911
2978
|
},
|
|
@@ -2918,8 +2985,8 @@ var styles = {
|
|
|
2918
2985
|
border: "none",
|
|
2919
2986
|
background: "rgba(255, 255, 255, 0.15)",
|
|
2920
2987
|
color: "#fff",
|
|
2921
|
-
width:
|
|
2922
|
-
height:
|
|
2988
|
+
width: 30,
|
|
2989
|
+
height: 30,
|
|
2923
2990
|
borderRadius: 8,
|
|
2924
2991
|
cursor: "pointer",
|
|
2925
2992
|
display: "flex",
|
|
@@ -2930,7 +2997,7 @@ var styles = {
|
|
|
2930
2997
|
// Messages area
|
|
2931
2998
|
messages: {
|
|
2932
2999
|
flex: 1,
|
|
2933
|
-
padding: "
|
|
3000
|
+
padding: "16px",
|
|
2934
3001
|
overflowY: "auto",
|
|
2935
3002
|
background: "#f8fafc",
|
|
2936
3003
|
display: "flex",
|
|
@@ -2945,10 +3012,10 @@ var styles = {
|
|
|
2945
3012
|
},
|
|
2946
3013
|
messageBubble: {
|
|
2947
3014
|
maxWidth: "85%",
|
|
2948
|
-
padding: "12px
|
|
3015
|
+
padding: "10px 12px",
|
|
2949
3016
|
borderRadius: 16,
|
|
2950
3017
|
lineHeight: 1.5,
|
|
2951
|
-
fontSize:
|
|
3018
|
+
fontSize: 13,
|
|
2952
3019
|
whiteSpace: "pre-wrap",
|
|
2953
3020
|
wordBreak: "break-word"
|
|
2954
3021
|
},
|
|
@@ -3062,7 +3129,7 @@ var styles = {
|
|
|
3062
3129
|
// Input area
|
|
3063
3130
|
inputWrapper: {
|
|
3064
3131
|
borderTop: "1px solid #e2e8f0",
|
|
3065
|
-
padding: "14px
|
|
3132
|
+
padding: "10px 14px",
|
|
3066
3133
|
display: "flex",
|
|
3067
3134
|
gap: 10,
|
|
3068
3135
|
alignItems: "flex-end",
|
|
@@ -3073,8 +3140,8 @@ var styles = {
|
|
|
3073
3140
|
resize: "none",
|
|
3074
3141
|
borderRadius: 12,
|
|
3075
3142
|
border: "1.5px solid #cbd5e1",
|
|
3076
|
-
padding: "10px
|
|
3077
|
-
fontSize:
|
|
3143
|
+
padding: "8px 10px",
|
|
3144
|
+
fontSize: 13,
|
|
3078
3145
|
fontFamily: "inherit",
|
|
3079
3146
|
lineHeight: 1.4,
|
|
3080
3147
|
transition: "border-color 0.2s"
|
|
@@ -3086,18 +3153,18 @@ var styles = {
|
|
|
3086
3153
|
sendButton: {
|
|
3087
3154
|
borderRadius: 12,
|
|
3088
3155
|
border: "none",
|
|
3089
|
-
padding: "
|
|
3156
|
+
padding: "8px 12px",
|
|
3090
3157
|
background: "linear-gradient(135deg, #10b981, #059669)",
|
|
3091
3158
|
color: "#fff",
|
|
3092
3159
|
cursor: "pointer",
|
|
3093
|
-
fontSize:
|
|
3160
|
+
fontSize: 13,
|
|
3094
3161
|
fontWeight: 600,
|
|
3095
3162
|
display: "flex",
|
|
3096
3163
|
alignItems: "center",
|
|
3097
3164
|
justifyContent: "center",
|
|
3098
3165
|
transition: "opacity 0.2s, transform 0.2s",
|
|
3099
|
-
minWidth:
|
|
3100
|
-
height:
|
|
3166
|
+
minWidth: 40,
|
|
3167
|
+
height: 40
|
|
3101
3168
|
},
|
|
3102
3169
|
// Status messages
|
|
3103
3170
|
statusNote: {
|
|
@@ -3127,42 +3194,42 @@ var FloatingChatBox = ({
|
|
|
3127
3194
|
open: openProp
|
|
3128
3195
|
}) => {
|
|
3129
3196
|
const isControlled = openProp !== void 0;
|
|
3130
|
-
const [internalOpen, setInternalOpen] =
|
|
3197
|
+
const [internalOpen, setInternalOpen] = useState5(false);
|
|
3131
3198
|
const open = isControlled ? openProp : internalOpen;
|
|
3132
|
-
const setOpen =
|
|
3199
|
+
const setOpen = useCallback4((value) => {
|
|
3133
3200
|
const newValue = typeof value === "function" ? value(open) : value;
|
|
3134
3201
|
if (!isControlled) {
|
|
3135
3202
|
setInternalOpen(newValue);
|
|
3136
3203
|
}
|
|
3137
3204
|
onOpenChange?.(newValue);
|
|
3138
3205
|
}, [isControlled, open, onOpenChange]);
|
|
3139
|
-
const [expanded, setExpanded] =
|
|
3140
|
-
const [messages, setMessages] =
|
|
3141
|
-
const [inputValue, setInputValue] =
|
|
3142
|
-
const [conversationId, setConversationId] =
|
|
3143
|
-
const [errorMessage, setErrorMessage] =
|
|
3144
|
-
const [isFocused, setIsFocused] =
|
|
3145
|
-
const [isMobile, setIsMobile] =
|
|
3146
|
-
const messagesEndRef =
|
|
3147
|
-
const messagesContainerRef =
|
|
3148
|
-
const chatBoxRef =
|
|
3149
|
-
const chatConfig =
|
|
3206
|
+
const [expanded, setExpanded] = useState5(false);
|
|
3207
|
+
const [messages, setMessages] = useState5([]);
|
|
3208
|
+
const [inputValue, setInputValue] = useState5("");
|
|
3209
|
+
const [conversationId, setConversationId] = useState5();
|
|
3210
|
+
const [errorMessage, setErrorMessage] = useState5(null);
|
|
3211
|
+
const [isFocused, setIsFocused] = useState5(false);
|
|
3212
|
+
const [isMobile, setIsMobile] = useState5(false);
|
|
3213
|
+
const messagesEndRef = useRef7(null);
|
|
3214
|
+
const messagesContainerRef = useRef7(null);
|
|
3215
|
+
const chatBoxRef = useRef7(null);
|
|
3216
|
+
const chatConfig = useMemo4(() => {
|
|
3150
3217
|
if (!baseUrl) return void 0;
|
|
3151
3218
|
return { baseUrl, accessToken, getAccessToken };
|
|
3152
3219
|
}, [accessToken, baseUrl, getAccessToken]);
|
|
3153
3220
|
const { sendMessage: sendMessage2, isStreaming, streamingText, completeResponse } = useSendMessageStream(chatConfig);
|
|
3154
3221
|
const canSend = Boolean(mapId) && Boolean(baseUrl) && inputValue.trim().length > 0 && !isStreaming;
|
|
3155
|
-
|
|
3222
|
+
useEffect6(() => {
|
|
3156
3223
|
if (open && isMobile) {
|
|
3157
3224
|
setExpanded(true);
|
|
3158
3225
|
}
|
|
3159
3226
|
}, [open, isMobile]);
|
|
3160
|
-
const scrollToBottom =
|
|
3227
|
+
const scrollToBottom = useCallback4(() => {
|
|
3161
3228
|
if (messagesEndRef.current) {
|
|
3162
3229
|
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
3163
3230
|
}
|
|
3164
3231
|
}, []);
|
|
3165
|
-
|
|
3232
|
+
useEffect6(() => {
|
|
3166
3233
|
if (open && messages.length === 0) {
|
|
3167
3234
|
setMessages([
|
|
3168
3235
|
{
|
|
@@ -3173,10 +3240,10 @@ var FloatingChatBox = ({
|
|
|
3173
3240
|
]);
|
|
3174
3241
|
}
|
|
3175
3242
|
}, [open, messages.length]);
|
|
3176
|
-
|
|
3243
|
+
useEffect6(() => {
|
|
3177
3244
|
scrollToBottom();
|
|
3178
3245
|
}, [messages, streamingText, scrollToBottom]);
|
|
3179
|
-
|
|
3246
|
+
useEffect6(() => {
|
|
3180
3247
|
if (!open) return;
|
|
3181
3248
|
if (isMobile && expanded) return;
|
|
3182
3249
|
const handleClickOutside = (event) => {
|
|
@@ -3189,7 +3256,7 @@ var FloatingChatBox = ({
|
|
|
3189
3256
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
3190
3257
|
};
|
|
3191
3258
|
}, [open, isMobile, expanded]);
|
|
3192
|
-
|
|
3259
|
+
useEffect6(() => {
|
|
3193
3260
|
if (typeof window === "undefined") return;
|
|
3194
3261
|
const mediaQuery = window.matchMedia("(max-width: 768px)");
|
|
3195
3262
|
const updateMobile = () => setIsMobile(mediaQuery.matches);
|
|
@@ -3207,7 +3274,7 @@ var FloatingChatBox = ({
|
|
|
3207
3274
|
}
|
|
3208
3275
|
};
|
|
3209
3276
|
}, []);
|
|
3210
|
-
|
|
3277
|
+
useEffect6(() => {
|
|
3211
3278
|
if (typeof document === "undefined") return;
|
|
3212
3279
|
if (!open || !isMobile) return;
|
|
3213
3280
|
document.body.style.overflow = "hidden";
|
|
@@ -3215,10 +3282,10 @@ var FloatingChatBox = ({
|
|
|
3215
3282
|
document.body.style.overflow = "";
|
|
3216
3283
|
};
|
|
3217
3284
|
}, [open, isMobile]);
|
|
3218
|
-
const addMessage =
|
|
3285
|
+
const addMessage = useCallback4((message) => {
|
|
3219
3286
|
setMessages((prev) => [...prev, message]);
|
|
3220
3287
|
}, []);
|
|
3221
|
-
const handleSend =
|
|
3288
|
+
const handleSend = useCallback4(async () => {
|
|
3222
3289
|
if (!mapId) {
|
|
3223
3290
|
setErrorMessage("Selecciona un mapa para usar el asistente.");
|
|
3224
3291
|
return;
|
|
@@ -3253,11 +3320,11 @@ var FloatingChatBox = ({
|
|
|
3253
3320
|
response
|
|
3254
3321
|
});
|
|
3255
3322
|
} catch (error) {
|
|
3256
|
-
setErrorMessage(
|
|
3323
|
+
setErrorMessage("Ocurri\xF3 un error al generar la respuesta.");
|
|
3257
3324
|
addMessage({
|
|
3258
3325
|
id: `error-${Date.now()}`,
|
|
3259
3326
|
role: "assistant",
|
|
3260
|
-
content:
|
|
3327
|
+
content: "\u274C Ocurri\xF3 un error al generar la respuesta."
|
|
3261
3328
|
});
|
|
3262
3329
|
}
|
|
3263
3330
|
}, [
|
|
@@ -3271,7 +3338,7 @@ var FloatingChatBox = ({
|
|
|
3271
3338
|
sendMessage2,
|
|
3272
3339
|
userId
|
|
3273
3340
|
]);
|
|
3274
|
-
const handleKeyDown =
|
|
3341
|
+
const handleKeyDown = useCallback4(
|
|
3275
3342
|
(event) => {
|
|
3276
3343
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
3277
3344
|
event.preventDefault();
|
|
@@ -3282,20 +3349,20 @@ var FloatingChatBox = ({
|
|
|
3282
3349
|
},
|
|
3283
3350
|
[canSend, handleSend]
|
|
3284
3351
|
);
|
|
3285
|
-
const handleFollowUpClick =
|
|
3352
|
+
const handleFollowUpClick = useCallback4((question) => {
|
|
3286
3353
|
setInputValue(question);
|
|
3287
3354
|
}, []);
|
|
3288
3355
|
const renderMetadata = (response) => {
|
|
3289
3356
|
if (!response?.metadata) return null;
|
|
3290
3357
|
const referencedLayers = response.metadata.referencedLayers;
|
|
3291
3358
|
if (!referencedLayers || referencedLayers.length === 0) return null;
|
|
3292
|
-
return /* @__PURE__ */
|
|
3293
|
-
/* @__PURE__ */
|
|
3294
|
-
/* @__PURE__ */
|
|
3359
|
+
return /* @__PURE__ */ jsxs6("div", { style: styles.metadataSection, children: [
|
|
3360
|
+
/* @__PURE__ */ jsxs6("div", { style: styles.metadataTitle, children: [
|
|
3361
|
+
/* @__PURE__ */ jsx7(LayersIcon, {}),
|
|
3295
3362
|
"Capas Analizadas"
|
|
3296
3363
|
] }),
|
|
3297
|
-
/* @__PURE__ */
|
|
3298
|
-
/* @__PURE__ */
|
|
3364
|
+
/* @__PURE__ */ jsx7("ul", { style: styles.metadataList, children: referencedLayers.map((layer, index) => /* @__PURE__ */ jsxs6("li", { style: styles.metadataItem, children: [
|
|
3365
|
+
/* @__PURE__ */ jsx7("strong", { children: layer.layerName }),
|
|
3299
3366
|
" (",
|
|
3300
3367
|
layer.featureCount,
|
|
3301
3368
|
" ",
|
|
@@ -3304,7 +3371,7 @@ var FloatingChatBox = ({
|
|
|
3304
3371
|
] }, index)) })
|
|
3305
3372
|
] });
|
|
3306
3373
|
};
|
|
3307
|
-
const handleActionClick =
|
|
3374
|
+
const handleActionClick = useCallback4((action) => {
|
|
3308
3375
|
if (isStreaming) return;
|
|
3309
3376
|
setOpen(false);
|
|
3310
3377
|
requestAnimationFrame(() => {
|
|
@@ -3313,9 +3380,9 @@ var FloatingChatBox = ({
|
|
|
3313
3380
|
}, [isStreaming, setOpen, onActionClick]);
|
|
3314
3381
|
const renderActions = (response) => {
|
|
3315
3382
|
if (!response?.suggestedActions?.length) return null;
|
|
3316
|
-
return /* @__PURE__ */
|
|
3317
|
-
/* @__PURE__ */
|
|
3318
|
-
/* @__PURE__ */
|
|
3383
|
+
return /* @__PURE__ */ jsxs6("div", { style: styles.actionsSection, children: [
|
|
3384
|
+
/* @__PURE__ */ jsx7("div", { style: styles.sectionLabel, children: "Acciones Sugeridas" }),
|
|
3385
|
+
/* @__PURE__ */ jsx7("div", { style: styles.actionsGrid, children: response.suggestedActions.map((action, index) => /* @__PURE__ */ jsx7(
|
|
3319
3386
|
"button",
|
|
3320
3387
|
{
|
|
3321
3388
|
type: "button",
|
|
@@ -3346,9 +3413,9 @@ var FloatingChatBox = ({
|
|
|
3346
3413
|
};
|
|
3347
3414
|
const renderFollowUps = (response) => {
|
|
3348
3415
|
if (!response?.followUpQuestions?.length) return null;
|
|
3349
|
-
return /* @__PURE__ */
|
|
3350
|
-
/* @__PURE__ */
|
|
3351
|
-
/* @__PURE__ */
|
|
3416
|
+
return /* @__PURE__ */ jsxs6("div", { style: styles.actionsSection, children: [
|
|
3417
|
+
/* @__PURE__ */ jsx7("div", { style: styles.sectionLabel, children: "Preguntas Relacionadas" }),
|
|
3418
|
+
/* @__PURE__ */ jsx7("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: response.followUpQuestions.map((question, index) => /* @__PURE__ */ jsx7(
|
|
3352
3419
|
"button",
|
|
3353
3420
|
{
|
|
3354
3421
|
type: "button",
|
|
@@ -3377,8 +3444,8 @@ var FloatingChatBox = ({
|
|
|
3377
3444
|
)) })
|
|
3378
3445
|
] });
|
|
3379
3446
|
};
|
|
3380
|
-
const chatContent = /* @__PURE__ */
|
|
3381
|
-
/* @__PURE__ */
|
|
3447
|
+
const chatContent = /* @__PURE__ */ jsxs6("div", { style: styles.root, children: [
|
|
3448
|
+
/* @__PURE__ */ jsx7("style", { children: `
|
|
3382
3449
|
@keyframes zenitBlink {
|
|
3383
3450
|
0%, 49% { opacity: 1; }
|
|
3384
3451
|
50%, 100% { opacity: 0; }
|
|
@@ -3421,11 +3488,13 @@ var FloatingChatBox = ({
|
|
|
3421
3488
|
@media (max-width: 768px) {
|
|
3422
3489
|
.zenit-chat-panel.zenit-chat-panel--fullscreen {
|
|
3423
3490
|
position: fixed !important;
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3491
|
+
left: 0 !important;
|
|
3492
|
+
right: 0 !important;
|
|
3493
|
+
top: 4rem !important;
|
|
3494
|
+
bottom: 0 !important;
|
|
3495
|
+
width: 100% !important;
|
|
3496
|
+
max-width: 100% !important;
|
|
3497
|
+
height: auto !important;
|
|
3429
3498
|
border-radius: 0 !important;
|
|
3430
3499
|
display: flex !important;
|
|
3431
3500
|
flex-direction: column !important;
|
|
@@ -3448,7 +3517,7 @@ var FloatingChatBox = ({
|
|
|
3448
3517
|
}
|
|
3449
3518
|
}
|
|
3450
3519
|
` }),
|
|
3451
|
-
open && /* @__PURE__ */
|
|
3520
|
+
open && /* @__PURE__ */ jsxs6(
|
|
3452
3521
|
"div",
|
|
3453
3522
|
{
|
|
3454
3523
|
ref: chatBoxRef,
|
|
@@ -3458,10 +3527,10 @@ var FloatingChatBox = ({
|
|
|
3458
3527
|
...expanded ? styles.panelExpanded : styles.panelNormal
|
|
3459
3528
|
},
|
|
3460
3529
|
children: [
|
|
3461
|
-
/* @__PURE__ */
|
|
3462
|
-
/* @__PURE__ */
|
|
3463
|
-
/* @__PURE__ */
|
|
3464
|
-
/* @__PURE__ */
|
|
3530
|
+
/* @__PURE__ */ jsxs6("header", { style: styles.header, children: [
|
|
3531
|
+
/* @__PURE__ */ jsx7("h3", { style: styles.title, children: "Asistente Zenit AI" }),
|
|
3532
|
+
/* @__PURE__ */ jsxs6("div", { style: styles.headerButtons, children: [
|
|
3533
|
+
/* @__PURE__ */ jsx7(
|
|
3465
3534
|
"button",
|
|
3466
3535
|
{
|
|
3467
3536
|
type: "button",
|
|
@@ -3474,10 +3543,10 @@ var FloatingChatBox = ({
|
|
|
3474
3543
|
e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
|
|
3475
3544
|
},
|
|
3476
3545
|
"aria-label": expanded ? "Contraer" : "Expandir",
|
|
3477
|
-
children: expanded ? /* @__PURE__ */
|
|
3546
|
+
children: expanded ? /* @__PURE__ */ jsx7(CollapseIcon, {}) : /* @__PURE__ */ jsx7(ExpandIcon, {})
|
|
3478
3547
|
}
|
|
3479
3548
|
),
|
|
3480
|
-
/* @__PURE__ */
|
|
3549
|
+
/* @__PURE__ */ jsx7(
|
|
3481
3550
|
"button",
|
|
3482
3551
|
{
|
|
3483
3552
|
type: "button",
|
|
@@ -3490,20 +3559,20 @@ var FloatingChatBox = ({
|
|
|
3490
3559
|
e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
|
|
3491
3560
|
},
|
|
3492
3561
|
"aria-label": "Cerrar",
|
|
3493
|
-
children: /* @__PURE__ */
|
|
3562
|
+
children: /* @__PURE__ */ jsx7(CloseIcon, {})
|
|
3494
3563
|
}
|
|
3495
3564
|
)
|
|
3496
3565
|
] })
|
|
3497
3566
|
] }),
|
|
3498
|
-
/* @__PURE__ */
|
|
3499
|
-
messages.map((message) => /* @__PURE__ */
|
|
3567
|
+
/* @__PURE__ */ jsxs6("div", { ref: messagesContainerRef, className: "zenit-ai-body", style: styles.messages, children: [
|
|
3568
|
+
messages.map((message) => /* @__PURE__ */ jsx7(
|
|
3500
3569
|
"div",
|
|
3501
3570
|
{
|
|
3502
3571
|
style: {
|
|
3503
3572
|
...styles.messageWrapper,
|
|
3504
3573
|
alignItems: message.role === "user" ? "flex-end" : "flex-start"
|
|
3505
3574
|
},
|
|
3506
|
-
children: /* @__PURE__ */
|
|
3575
|
+
children: /* @__PURE__ */ jsxs6(
|
|
3507
3576
|
"div",
|
|
3508
3577
|
{
|
|
3509
3578
|
style: {
|
|
@@ -3511,7 +3580,7 @@ var FloatingChatBox = ({
|
|
|
3511
3580
|
...message.role === "user" ? styles.userMessage : styles.assistantMessage
|
|
3512
3581
|
},
|
|
3513
3582
|
children: [
|
|
3514
|
-
message.role === "assistant" ? /* @__PURE__ */
|
|
3583
|
+
message.role === "assistant" ? /* @__PURE__ */ jsx7(MarkdownRenderer, { content: message.content }) : message.content,
|
|
3515
3584
|
message.role === "assistant" && renderMetadata(message.response),
|
|
3516
3585
|
message.role === "assistant" && renderActions(message.response),
|
|
3517
3586
|
message.role === "assistant" && renderFollowUps(message.response)
|
|
@@ -3521,39 +3590,39 @@ var FloatingChatBox = ({
|
|
|
3521
3590
|
},
|
|
3522
3591
|
message.id
|
|
3523
3592
|
)),
|
|
3524
|
-
isStreaming && /* @__PURE__ */
|
|
3593
|
+
isStreaming && /* @__PURE__ */ jsx7(
|
|
3525
3594
|
"div",
|
|
3526
3595
|
{
|
|
3527
3596
|
style: {
|
|
3528
3597
|
...styles.messageWrapper,
|
|
3529
3598
|
alignItems: "flex-start"
|
|
3530
3599
|
},
|
|
3531
|
-
children: /* @__PURE__ */
|
|
3600
|
+
children: /* @__PURE__ */ jsx7(
|
|
3532
3601
|
"div",
|
|
3533
3602
|
{
|
|
3534
3603
|
style: {
|
|
3535
3604
|
...styles.messageBubble,
|
|
3536
3605
|
...styles.assistantMessage
|
|
3537
3606
|
},
|
|
3538
|
-
children: streamingText ? /* @__PURE__ */
|
|
3539
|
-
/* @__PURE__ */
|
|
3540
|
-
/* @__PURE__ */
|
|
3541
|
-
] }) : /* @__PURE__ */
|
|
3542
|
-
/* @__PURE__ */
|
|
3543
|
-
/* @__PURE__ */
|
|
3544
|
-
/* @__PURE__ */
|
|
3545
|
-
/* @__PURE__ */
|
|
3546
|
-
/* @__PURE__ */
|
|
3607
|
+
children: streamingText ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
3608
|
+
/* @__PURE__ */ jsx7(MarkdownRenderer, { content: streamingText }),
|
|
3609
|
+
/* @__PURE__ */ jsx7("span", { style: styles.cursor })
|
|
3610
|
+
] }) : /* @__PURE__ */ jsxs6("div", { style: styles.thinkingText, children: [
|
|
3611
|
+
/* @__PURE__ */ jsx7("span", { children: "Pensando" }),
|
|
3612
|
+
/* @__PURE__ */ jsxs6("div", { style: styles.typingIndicator, children: [
|
|
3613
|
+
/* @__PURE__ */ jsx7("div", { className: "zenit-typing-dot", style: styles.typingDot }),
|
|
3614
|
+
/* @__PURE__ */ jsx7("div", { className: "zenit-typing-dot", style: styles.typingDot }),
|
|
3615
|
+
/* @__PURE__ */ jsx7("div", { className: "zenit-typing-dot", style: styles.typingDot })
|
|
3547
3616
|
] })
|
|
3548
3617
|
] })
|
|
3549
3618
|
}
|
|
3550
3619
|
)
|
|
3551
3620
|
}
|
|
3552
3621
|
),
|
|
3553
|
-
/* @__PURE__ */
|
|
3622
|
+
/* @__PURE__ */ jsx7("div", { ref: messagesEndRef })
|
|
3554
3623
|
] }),
|
|
3555
|
-
/* @__PURE__ */
|
|
3556
|
-
/* @__PURE__ */
|
|
3624
|
+
/* @__PURE__ */ jsxs6("div", { className: "zenit-ai-input-area", style: styles.inputWrapper, children: [
|
|
3625
|
+
/* @__PURE__ */ jsx7(
|
|
3557
3626
|
"textarea",
|
|
3558
3627
|
{
|
|
3559
3628
|
style: {
|
|
@@ -3570,7 +3639,7 @@ var FloatingChatBox = ({
|
|
|
3570
3639
|
disabled: !mapId || !baseUrl || isStreaming
|
|
3571
3640
|
}
|
|
3572
3641
|
),
|
|
3573
|
-
/* @__PURE__ */
|
|
3642
|
+
/* @__PURE__ */ jsx7(
|
|
3574
3643
|
"button",
|
|
3575
3644
|
{
|
|
3576
3645
|
type: "button",
|
|
@@ -3579,36 +3648,38 @@ var FloatingChatBox = ({
|
|
|
3579
3648
|
onClick: () => void handleSend(),
|
|
3580
3649
|
disabled: !canSend,
|
|
3581
3650
|
"aria-label": "Enviar mensaje",
|
|
3582
|
-
children: /* @__PURE__ */
|
|
3651
|
+
children: /* @__PURE__ */ jsx7(SendIcon, {})
|
|
3583
3652
|
}
|
|
3584
3653
|
)
|
|
3585
3654
|
] }),
|
|
3586
|
-
errorMessage && /* @__PURE__ */
|
|
3587
|
-
|
|
3588
|
-
!
|
|
3655
|
+
errorMessage && /* @__PURE__ */ jsx7("div", { style: styles.errorText, children: errorMessage }),
|
|
3656
|
+
isStreaming && !errorMessage && /* @__PURE__ */ jsx7("div", { style: styles.statusNote, children: "Generando sugerencias..." }),
|
|
3657
|
+
!mapId && !errorMessage && /* @__PURE__ */ jsx7("div", { style: styles.statusNote, children: "Selecciona un mapa para usar el asistente" }),
|
|
3658
|
+
!baseUrl && !errorMessage && /* @__PURE__ */ jsx7("div", { style: styles.statusNote, children: "Configura la baseUrl del SDK" })
|
|
3589
3659
|
]
|
|
3590
3660
|
}
|
|
3591
3661
|
),
|
|
3592
|
-
!(hideButton && !open) && /* @__PURE__ */
|
|
3662
|
+
!(hideButton && !open) && /* @__PURE__ */ jsx7(
|
|
3593
3663
|
"button",
|
|
3594
3664
|
{
|
|
3595
3665
|
type: "button",
|
|
3596
3666
|
className: `zenit-ai-button ${open ? "open" : ""}${open && isMobile ? " zenit-ai-button--hidden-mobile" : ""}`,
|
|
3597
3667
|
style: {
|
|
3598
3668
|
...styles.floatingButton,
|
|
3599
|
-
...open ? styles.floatingButtonOpen : isMobile ? styles.floatingButtonMobile : styles.floatingButtonClosed
|
|
3669
|
+
...open ? styles.floatingButtonOpen : isMobile ? styles.floatingButtonMobile : styles.floatingButtonClosed,
|
|
3670
|
+
zIndex: open ? 100001 : 99999
|
|
3600
3671
|
},
|
|
3601
3672
|
onClick: () => setOpen((prev) => !prev),
|
|
3602
3673
|
"aria-label": open ? "Cerrar asistente" : "Abrir asistente Zenit AI",
|
|
3603
|
-
children: open ? /* @__PURE__ */
|
|
3604
|
-
/* @__PURE__ */
|
|
3605
|
-
!isMobile && /* @__PURE__ */
|
|
3674
|
+
children: open ? /* @__PURE__ */ jsx7(CloseIcon, {}) : /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
3675
|
+
/* @__PURE__ */ jsx7(ChatIcon, {}),
|
|
3676
|
+
!isMobile && /* @__PURE__ */ jsx7("span", { children: "Asistente IA" })
|
|
3606
3677
|
] })
|
|
3607
3678
|
}
|
|
3608
3679
|
)
|
|
3609
3680
|
] });
|
|
3610
3681
|
if (typeof document !== "undefined") {
|
|
3611
|
-
return
|
|
3682
|
+
return createPortal2(chatContent, document.body);
|
|
3612
3683
|
}
|
|
3613
3684
|
return chatContent;
|
|
3614
3685
|
};
|
|
@@ -3651,4 +3722,4 @@ export {
|
|
|
3651
3722
|
useSendMessageStream,
|
|
3652
3723
|
FloatingChatBox
|
|
3653
3724
|
};
|
|
3654
|
-
//# sourceMappingURL=chunk-
|
|
3725
|
+
//# sourceMappingURL=chunk-PCTRVN4O.mjs.map
|