zenit-sdk 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -456,6 +456,14 @@ var LayerGeoJson = ({
456
456
  onEachFeature,
457
457
  onPolygonLabel
458
458
  }) => {
459
+ const styleFnRef = useRef(styleFn);
460
+ const onEachFeatureRef = useRef(onEachFeature);
461
+ useEffect(() => {
462
+ styleFnRef.current = styleFn;
463
+ }, [styleFn]);
464
+ useEffect(() => {
465
+ onEachFeatureRef.current = onEachFeature;
466
+ }, [onEachFeature]);
459
467
  const safeData = useMemo(() => sanitizeGeoJson(data, String(layerId)), [data, layerId]);
460
468
  const features = useMemo(() => safeData.features ?? [], [safeData]);
461
469
  const fillFeatures = useMemo(() => features.filter(isNonPointGeometry), [features]);
@@ -499,14 +507,14 @@ var LayerGeoJson = ({
499
507
  if (!isValidLatLng(latlng)) {
500
508
  return createInvisibleFallbackClusterMarker();
501
509
  }
502
- const style = styleFn(feature, layerType, baseOpacity);
510
+ const style = styleFnRef.current(feature, layerType, baseOpacity);
503
511
  return L.marker(latlng, {
504
512
  icon: createPointDivIcon(style, isMobile),
505
513
  pane: clusterPaneName,
506
514
  interactive: true
507
515
  });
508
516
  },
509
- onEachFeature
517
+ onEachFeature: (feature, layer) => onEachFeatureRef.current(feature, layer)
510
518
  });
511
519
  clusterLayer.addLayer(geoJsonLayer);
512
520
  return () => {
@@ -521,11 +529,9 @@ var LayerGeoJson = ({
521
529
  isMobile,
522
530
  layerType,
523
531
  mapInstance,
524
- onEachFeature,
525
532
  panesReady,
526
533
  pointsData,
527
- resolvedPointsPane,
528
- styleFn
534
+ resolvedPointsPane
529
535
  ]);
530
536
  return /* @__PURE__ */ jsxs(Fragment, { children: [
531
537
  fillData && /* @__PURE__ */ jsx(
@@ -634,6 +640,55 @@ function useGeolocation(options) {
634
640
 
635
641
  // src/react/map/map-utils.ts
636
642
  import L2 from "leaflet";
643
+
644
+ // src/config/modalWhitelist.ts
645
+ var SECTOR_MODAL_WHITELIST = [
646
+ { key: "Sector", label: "Sector" },
647
+ { key: "Promotor", label: "Promotor" },
648
+ { key: "Capital Total", label: "Capital Total" },
649
+ { key: "Total Capital Mora", label: "Capital en Mora" },
650
+ { key: "Tendencia Mora", label: "Tendencia de Mora", hint: "trend_icon" },
651
+ { key: "Tendencia Capital", label: "Tendencia de Capital", hint: "trend_icon" },
652
+ { key: "Tendencia Castigos", label: "Tendencia de Castigos", hint: "trend_icon" },
653
+ { key: "Impacto Sector", label: "Impacto del Sector" },
654
+ { key: "Total Clientes Sector", label: "Total de Clientes" },
655
+ { key: "Total Clientes Sanos", label: "Clientes Sanos" },
656
+ { key: "Total Clientes Morosos", label: "Clientes en Mora" },
657
+ { key: "Total Clientes Castigados", label: "Clientes Castigados" },
658
+ { key: "Total Clientes Nuevos", label: "Clientes Nuevos" },
659
+ { key: "Total Clientes Salidos", label: "Clientes Salidos" },
660
+ { key: "Insights", label: "An\xE1lisis IA", hint: "collapsible" },
661
+ { key: "Recomendaciones", label: "Recomendaciones IA", hint: "collapsible" }
662
+ ];
663
+ var CLIENTE_MODAL_WHITELIST = [
664
+ { key: "nombre del cliente", label: "Nombre del Cliente" },
665
+ { key: "dpi", label: "DPI" },
666
+ { key: "kpi", label: "Estado", hint: "kpi_badge" },
667
+ { key: "tel principal", label: "Tel\xE9fono", hint: "phone_link" },
668
+ { key: "capital concedido", label: "Capital Concedido" },
669
+ { key: "mora", label: "Monto en Mora", hint: "mora_alert" },
670
+ { key: "etapa", label: "Etapa del Cr\xE9dito" },
671
+ { key: "prestamo", label: "No. de Pr\xE9stamo" },
672
+ { key: "sucursal", label: "Sucursal", aliases: ["nombre sucursal"] }
673
+ ];
674
+ function applyModalWhitelist(rawData, whitelist) {
675
+ const keys = Object.keys(rawData ?? {});
676
+ return whitelist.map(({ key, label, hint, aliases = [] }) => {
677
+ const keysToTry = [key, ...aliases];
678
+ let value = void 0;
679
+ for (const k of keysToTry) {
680
+ const match = keys.find((rawKey) => rawKey.toLowerCase() === k.toLowerCase());
681
+ if (match !== void 0 && rawData[match] !== null && rawData[match] !== void 0) {
682
+ value = rawData[match];
683
+ break;
684
+ }
685
+ }
686
+ if (value === void 0) return null;
687
+ return { label, value, hint: hint ?? null };
688
+ }).filter((entry) => Boolean(entry));
689
+ }
690
+
691
+ // src/react/map/map-utils.ts
637
692
  var POPUP_STYLE_ID = "zenit-leaflet-popup-styles";
638
693
  var POPUP_EXCLUDED_KEYS = /* @__PURE__ */ new Set(["geom", "geometry", "_private"]);
639
694
  var POPUP_TITLE_KEYS = ["id", "nombre", "name", "title", "titulo", "cluster"];
@@ -870,6 +925,10 @@ function shouldIncludePopupEntry(key, value) {
870
925
  return true;
871
926
  }
872
927
  function createPopupContent(properties) {
928
+ const whitelistedRows = buildWhitelistedRows(properties);
929
+ if (whitelistedRows) {
930
+ return whitelistedRows;
931
+ }
873
932
  const header = findHeaderProperties(properties);
874
933
  const headerText = header.title?.value ?? extractPopupHeader(properties);
875
934
  const usedKeys = new Set([header.title?.key, header.badge?.key, header.description?.key].filter(Boolean));
@@ -909,6 +968,37 @@ function createPopupContent(properties) {
909
968
  }).join("");
910
969
  return `<div>${colorBar}${headerHtml}${descriptionHtml}${rowsHtml}</div>`;
911
970
  }
971
+ function buildWhitelistedRows(properties) {
972
+ const whitelist = selectModalWhitelist(properties);
973
+ if (!whitelist) return null;
974
+ const entries = applyModalWhitelist(properties, whitelist);
975
+ if (entries.length === 0) {
976
+ return '<div style="padding:8px 0; color:#64748b; text-align:center;">Sin datos disponibles</div>';
977
+ }
978
+ const rowsHtml = entries.map(({ label, value }) => {
979
+ const valueHtml = renderPopupValue(value);
980
+ return `
981
+ <div style="display:grid; grid-template-columns:minmax(90px, 35%) 1fr; gap:8px; padding:6px 0; border-bottom:1px solid #e2e8f0;">
982
+ <div style="font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.04em; color:#64748b;">${escapeHtml(label)}</div>
983
+ <div style="font-size:13px; color:#0f172a; word-break:break-word;">${valueHtml}</div>
984
+ </div>
985
+ `;
986
+ }).join("");
987
+ return `<div>${rowsHtml}</div>`;
988
+ }
989
+ function countWhitelistMatches(properties, whitelist) {
990
+ const keys = Object.keys(properties).map((key) => key.toLowerCase());
991
+ return whitelist.reduce((count, item) => {
992
+ const candidates = [item.key, ...item.aliases ?? []].map((candidate) => candidate.toLowerCase());
993
+ return candidates.some((candidate) => keys.includes(candidate)) ? count + 1 : count;
994
+ }, 0);
995
+ }
996
+ function selectModalWhitelist(properties) {
997
+ const sectorMatches = countWhitelistMatches(properties, SECTOR_MODAL_WHITELIST);
998
+ const clienteMatches = countWhitelistMatches(properties, CLIENTE_MODAL_WHITELIST);
999
+ if (sectorMatches === 0 && clienteMatches === 0) return null;
1000
+ return sectorMatches >= clienteMatches ? SECTOR_MODAL_WHITELIST : CLIENTE_MODAL_WHITELIST;
1001
+ }
912
1002
  function isPolygonType(layerType, geometryType) {
913
1003
  const candidate = (layerType ?? geometryType ?? "").toLowerCase();
914
1004
  return candidate === "polygon" || candidate === "multipolygon";
@@ -1437,6 +1527,14 @@ function pickIntersectFeature(params) {
1437
1527
  selectedIdx: candidates.findIndex((candidate) => candidate === feature),
1438
1528
  reason
1439
1529
  });
1530
+ if (clickIntent === "point") {
1531
+ const anyPoint = candidates.find(
1532
+ (c) => isCandidateGeometryType(c, POINT_GEOMETRY_TYPES2)
1533
+ );
1534
+ if (anyPoint) {
1535
+ return getResult(anyPoint, "point:first-point-geometry");
1536
+ }
1537
+ }
1440
1538
  const sameLayer = candidates.filter(
1441
1539
  (candidate) => isLayerIdMatch(candidateLayerId(candidate), expectedLayerId)
1442
1540
  );
@@ -1873,7 +1971,7 @@ var ZenitMap = forwardRef(({
1873
1971
  const ensureLayerPanes = useCallback2(
1874
1972
  (targetMap, targetLayers) => {
1875
1973
  const fillBaseZIndex = 400;
1876
- const pointsBaseZIndex = 700;
1974
+ const pointsBaseZIndex = 750;
1877
1975
  targetLayers.forEach((layer) => {
1878
1976
  const order = Number.isFinite(layer.displayOrder) ? layer.displayOrder : 0;
1879
1977
  const orderOffset = Math.max(0, Math.min(order, 150));
@@ -1957,7 +2055,10 @@ var ZenitMap = forwardRef(({
1957
2055
  className: "zenit-map-tooltip"
1958
2056
  });
1959
2057
  }
1960
- layer.on("click", () => {
2058
+ layer.on("click", (e) => {
2059
+ if (clickIntent === "point") {
2060
+ L4.DomEvent.stopPropagation(e);
2061
+ }
1961
2062
  if (featureInfoMode === "popup" && client && layerId !== void 0 && !extractDescriptionValue(feature?.properties) && feature?.geometry) {
1962
2063
  if (DEV_MODE2) {
1963
2064
  console.debug("[ZenitMap] click/intersect:start", {
@@ -2057,11 +2158,16 @@ var ZenitMap = forwardRef(({
2057
2158
  properties: feature?.properties ?? void 0
2058
2159
  });
2059
2160
  }, [currentZoom, resolveLayerStyle]);
2060
- const makeStyleFnForLayer = useCallback2((layerId) => {
2061
- return (feature, layerType, baseOpacity) => {
2062
- return buildLayerStyle(layerId, baseOpacity ?? 1, feature, layerType);
2063
- };
2064
- }, [buildLayerStyle]);
2161
+ const styleFnByLayerId = useMemo3(() => {
2162
+ const next = /* @__PURE__ */ new Map();
2163
+ orderedLayers.forEach((layerState) => {
2164
+ const layerId = layerState.mapLayer.layerId;
2165
+ next.set(String(layerId), (feature, layerType, baseOpacity) => {
2166
+ return buildLayerStyle(layerId, baseOpacity ?? 1, feature, layerType);
2167
+ });
2168
+ });
2169
+ return next;
2170
+ }, [buildLayerStyle, orderedLayers]);
2065
2171
  useImperativeHandle(ref, () => ({
2066
2172
  setLayerOpacity: (layerId, opacity) => {
2067
2173
  upsertUiOverride(layerId, { overrideOpacity: opacity });
@@ -2228,7 +2334,7 @@ var ZenitMap = forwardRef(({
2228
2334
  fillPaneName,
2229
2335
  pointsPaneName,
2230
2336
  layerType,
2231
- styleFn: makeStyleFnForLayer(layerState.mapLayer.layerId),
2337
+ styleFn: styleFnByLayerId.get(String(layerState.mapLayer.layerId)) ?? ((feature, layerType2, baseOpacity2) => buildLayerStyle(layerState.mapLayer.layerId, baseOpacity2 ?? 1, feature, layerType2)),
2232
2338
  onEachFeature: overlayOnEachFeature,
2233
2339
  onPolygonLabel: labelKey ? (feature, layer) => {
2234
2340
  const geometryType = feature?.geometry?.type;
@@ -2372,7 +2478,7 @@ var ZenitMap = forwardRef(({
2372
2478
  ZenitMap.displayName = "ZenitMap";
2373
2479
 
2374
2480
  // src/react/ZenitLayerManager.tsx
2375
- import React6, { useEffect as useEffect6, useMemo as useMemo4, useRef as useRef6, useState as useState3 } from "react";
2481
+ import React7, { useEffect as useEffect6, useMemo as useMemo4, useRef as useRef6, useState as useState3 } from "react";
2376
2482
 
2377
2483
  // src/react/icons.tsx
2378
2484
  import { Eye, EyeOff, ChevronDown, ChevronLeft, ChevronRight, Layers, Upload, X, ZoomIn } from "lucide-react";
@@ -2730,9 +2836,191 @@ var ZenitSelect = ({
2730
2836
  ] });
2731
2837
  };
2732
2838
 
2839
+ // src/react/ui/ZenitCombobox.tsx
2840
+ import React6 from "react";
2841
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2842
+ var ZenitCombobox = ({
2843
+ options,
2844
+ value,
2845
+ onChange,
2846
+ placeholder = "Seleccionar\u2026",
2847
+ searchPlaceholder = "Buscar\u2026",
2848
+ disabled = false
2849
+ }) => {
2850
+ const rootRef = React6.useRef(null);
2851
+ const [isOpen, setIsOpen] = React6.useState(false);
2852
+ const [query, setQuery] = React6.useState("");
2853
+ const filteredOptions = React6.useMemo(() => {
2854
+ const normalized = query.trim().toLowerCase();
2855
+ if (!normalized) return options;
2856
+ return options.filter((option) => option.toLowerCase().includes(normalized));
2857
+ }, [options, query]);
2858
+ React6.useEffect(() => {
2859
+ if (!isOpen) return;
2860
+ const onClickOutside = (event) => {
2861
+ if (!rootRef.current?.contains(event.target)) {
2862
+ setIsOpen(false);
2863
+ }
2864
+ };
2865
+ const onEscape = (event) => {
2866
+ if (event.key === "Escape") {
2867
+ setIsOpen(false);
2868
+ }
2869
+ };
2870
+ document.addEventListener("mousedown", onClickOutside);
2871
+ document.addEventListener("keydown", onEscape);
2872
+ return () => {
2873
+ document.removeEventListener("mousedown", onClickOutside);
2874
+ document.removeEventListener("keydown", onEscape);
2875
+ };
2876
+ }, [isOpen]);
2877
+ React6.useEffect(() => {
2878
+ if (!isOpen) {
2879
+ setQuery("");
2880
+ }
2881
+ }, [isOpen]);
2882
+ return /* @__PURE__ */ jsxs5("div", { ref: rootRef, className: "zenit-combobox-root", style: { position: "relative" }, children: [
2883
+ /* @__PURE__ */ jsx5("style", { children: `
2884
+ .zenit-combobox-trigger {
2885
+ width: 100%;
2886
+ min-height: 40px;
2887
+ height: 40px;
2888
+ border: 1px solid #cbd5e1;
2889
+ border-radius: 6px;
2890
+ background: #ffffff;
2891
+ color: #0f172a;
2892
+ display: inline-flex;
2893
+ align-items: center;
2894
+ padding: 0 12px;
2895
+ font-size: 14px;
2896
+ line-height: 1.25;
2897
+ cursor: pointer;
2898
+ text-align: left;
2899
+ }
2900
+ .zenit-combobox-trigger.is-placeholder {
2901
+ color: #64748b;
2902
+ }
2903
+ .zenit-combobox-trigger:disabled {
2904
+ opacity: 0.6;
2905
+ cursor: not-allowed;
2906
+ }
2907
+ .zenit-combobox-content {
2908
+ position: absolute;
2909
+ top: calc(100% + 6px);
2910
+ left: 0;
2911
+ right: 0;
2912
+ border: 1px solid #cbd5e1;
2913
+ border-radius: 6px;
2914
+ background: #ffffff;
2915
+ box-shadow: 0 10px 25px rgba(15, 23, 42, 0.18);
2916
+ padding: 8px;
2917
+ z-index: 4000;
2918
+ }
2919
+ .zenit-combobox-search {
2920
+ width: 100%;
2921
+ min-height: 36px;
2922
+ border: 1px solid #cbd5e1;
2923
+ border-radius: 6px;
2924
+ background: #ffffff;
2925
+ color: #0f172a;
2926
+ padding: 0 10px;
2927
+ font-size: 14px;
2928
+ margin-bottom: 8px;
2929
+ box-sizing: border-box;
2930
+ }
2931
+ .zenit-combobox-list {
2932
+ max-height: 220px;
2933
+ overflow-y: auto;
2934
+ }
2935
+ .zenit-combobox-item {
2936
+ width: 100%;
2937
+ border-radius: 4px;
2938
+ color: #0f172a;
2939
+ font-size: 14px;
2940
+ min-height: 34px;
2941
+ padding: 8px 10px;
2942
+ cursor: pointer;
2943
+ user-select: none;
2944
+ }
2945
+ .zenit-combobox-item:hover { background: #f1f5f9; }
2946
+ .zenit-combobox-item.is-selected { background: #e2e8f0; font-weight: 600; }
2947
+ ` }),
2948
+ /* @__PURE__ */ jsx5(
2949
+ "button",
2950
+ {
2951
+ type: "button",
2952
+ className: `zenit-combobox-trigger${!value ? " is-placeholder" : ""}`,
2953
+ disabled,
2954
+ onClick: () => !disabled && setIsOpen((prev) => !prev),
2955
+ children: value || placeholder
2956
+ }
2957
+ ),
2958
+ isOpen && /* @__PURE__ */ jsxs5("div", { className: "zenit-combobox-content", children: [
2959
+ /* @__PURE__ */ jsx5(
2960
+ "input",
2961
+ {
2962
+ className: "zenit-combobox-search",
2963
+ value: query,
2964
+ onChange: (event) => setQuery(event.target.value),
2965
+ placeholder: searchPlaceholder,
2966
+ autoFocus: true
2967
+ }
2968
+ ),
2969
+ /* @__PURE__ */ jsxs5("div", { className: "zenit-combobox-list", children: [
2970
+ filteredOptions.length === 0 && /* @__PURE__ */ jsx5("div", { className: "zenit-combobox-item", style: { color: "#64748b", cursor: "default" }, children: "Sin coincidencias" }),
2971
+ filteredOptions.map((option) => /* @__PURE__ */ jsx5(
2972
+ "div",
2973
+ {
2974
+ className: `zenit-combobox-item${option === value ? " is-selected" : ""}`,
2975
+ onClick: () => {
2976
+ onChange(option);
2977
+ setIsOpen(false);
2978
+ },
2979
+ children: option
2980
+ },
2981
+ option
2982
+ ))
2983
+ ] })
2984
+ ] })
2985
+ ] });
2986
+ };
2987
+
2733
2988
  // src/react/ZenitLayerManager.tsx
2734
- import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2989
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2735
2990
  var FLOAT_TOLERANCE = 1e-3;
2991
+ var CATALOG_FIELD_BLACKLIST = /* @__PURE__ */ new Set([
2992
+ "mapids",
2993
+ "mapId",
2994
+ "mapIDs",
2995
+ "mapId",
2996
+ "field",
2997
+ "Field",
2998
+ "objectid",
2999
+ "OBJECTID",
3000
+ "objectId",
3001
+ "gforms",
3002
+ "GFORMS",
3003
+ "nomina",
3004
+ "NOMINA",
3005
+ "shape_area",
3006
+ "SHAPE_AREA",
3007
+ "shape_leng",
3008
+ "SHAPE_LENG",
3009
+ "fid",
3010
+ "FID",
3011
+ "gid",
3012
+ "GID",
3013
+ "created_at",
3014
+ "updated_at",
3015
+ "created_user",
3016
+ "last_edited_user",
3017
+ "globalid",
3018
+ "GLOBALID"
3019
+ ]);
3020
+ function isFieldVisible(key) {
3021
+ return !CATALOG_FIELD_BLACKLIST.has(key) && !key.startsWith("_") && !key.startsWith("__");
3022
+ }
3023
+ var matchesWhitelist = (key, whitelist) => whitelist.some((w) => w.toUpperCase() === key.toUpperCase());
2736
3024
  function areEffectiveStatesEqual(a, b) {
2737
3025
  if (a.length !== b.length) return false;
2738
3026
  return a.every((state, index) => {
@@ -2771,7 +3059,9 @@ var ZenitLayerManager = ({
2771
3059
  layerFeatureCounts,
2772
3060
  mapLayers,
2773
3061
  onApplyLayerFilter,
2774
- onClearLayerFilter
3062
+ onClearLayerFilter,
3063
+ availableFilterLayers = [],
3064
+ filterFieldWhitelist = []
2775
3065
  }) => {
2776
3066
  const [map, setMap] = useState3(null);
2777
3067
  const [loadingMap, setLoadingMap] = useState3(false);
@@ -2783,6 +3073,7 @@ var ZenitLayerManager = ({
2783
3073
  const [selectedFilterField, setSelectedFilterField] = useState3("");
2784
3074
  const [selectedFilterValue, setSelectedFilterValue] = useState3("");
2785
3075
  const [catalogByLayerField, setCatalogByLayerField] = useState3({});
3076
+ const [catalogFieldsByLayer, setCatalogFieldsByLayer] = useState3({});
2786
3077
  const [loadingCatalog, setLoadingCatalog] = useState3(false);
2787
3078
  const [applyingFilter, setApplyingFilter] = useState3(false);
2788
3079
  const [filterError, setFilterError] = useState3(null);
@@ -2829,7 +3120,7 @@ var ZenitLayerManager = ({
2829
3120
  });
2830
3121
  return index;
2831
3122
  }, [map, mapLayers]);
2832
- const resolveUserOpacity = React6.useCallback((state) => {
3123
+ const resolveUserOpacity = React7.useCallback((state) => {
2833
3124
  if (typeof state.overrideOpacity === "number") return state.overrideOpacity;
2834
3125
  if (typeof state.overrideOpacity === "string") {
2835
3126
  const parsed = Number.parseFloat(state.overrideOpacity);
@@ -2837,7 +3128,7 @@ var ZenitLayerManager = ({
2837
3128
  }
2838
3129
  return state.opacity ?? 1;
2839
3130
  }, []);
2840
- const resolveEffectiveOpacity = React6.useCallback(
3131
+ const resolveEffectiveOpacity = React7.useCallback(
2841
3132
  (layerId, userOpacity) => {
2842
3133
  if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
2843
3134
  return userOpacity;
@@ -2922,7 +3213,7 @@ var ZenitLayerManager = ({
2922
3213
  mapZoom,
2923
3214
  onLayerStatesChange
2924
3215
  ]);
2925
- const updateLayerVisible = React6.useCallback(
3216
+ const updateLayerVisible = React7.useCallback(
2926
3217
  (layerId, visible) => {
2927
3218
  if (!onLayerStatesChange) return;
2928
3219
  const next = effectiveStates.map(
@@ -2932,7 +3223,7 @@ var ZenitLayerManager = ({
2932
3223
  },
2933
3224
  [effectiveStates, onLayerStatesChange]
2934
3225
  );
2935
- const updateLayerOpacity = React6.useCallback(
3226
+ const updateLayerOpacity = React7.useCallback(
2936
3227
  (layerId, opacity) => {
2937
3228
  if (!onLayerStatesChange) return;
2938
3229
  const adjustedOpacity = resolveEffectiveOpacity(layerId, opacity);
@@ -2943,7 +3234,7 @@ var ZenitLayerManager = ({
2943
3234
  },
2944
3235
  [effectiveStates, onLayerStatesChange, resolveEffectiveOpacity]
2945
3236
  );
2946
- const resolveFeatureCount = React6.useCallback(
3237
+ const resolveFeatureCount = React7.useCallback(
2947
3238
  (layerId, layer) => {
2948
3239
  const resolvedFeatureCount = layerFeatureCounts?.[layerId] ?? layerFeatureCounts?.[String(layerId)];
2949
3240
  if (typeof resolvedFeatureCount === "number") return resolvedFeatureCount;
@@ -2990,22 +3281,31 @@ var ZenitLayerManager = ({
2990
3281
  });
2991
3282
  }, [map?.mapLayers, mapLayers]);
2992
3283
  const filterableLayers = useMemo4(() => {
3284
+ const forcedLayerIds = new Set(availableFilterLayers.map((layerId) => String(layerId)));
2993
3285
  return decoratedLayers.filter((entry) => {
2994
3286
  const prefilters = entry.mapLayer.layerConfig?.prefilters;
2995
- return !!prefilters && Object.keys(prefilters).length > 0;
3287
+ if (prefilters && Object.keys(prefilters).length > 0) return true;
3288
+ if (forcedLayerIds.has(String(entry.mapLayer.layerId))) return true;
3289
+ const layerType = (entry.mapLayer.layerType ?? entry.layer?.layerType ?? "").toString().toLowerCase();
3290
+ return layerType === "multipolygon";
2996
3291
  });
2997
- }, [decoratedLayers]);
3292
+ }, [availableFilterLayers, decoratedLayers]);
2998
3293
  const selectedFilterLayer = useMemo4(
2999
3294
  () => filterableLayers.find((layer) => String(layer.mapLayer.layerId) === selectedFilterLayerId) ?? null,
3000
3295
  [filterableLayers, selectedFilterLayerId]
3001
3296
  );
3002
3297
  const filterFields = useMemo4(() => {
3003
- const prefilters = selectedFilterLayer?.mapLayer.layerConfig?.prefilters;
3004
- return prefilters ? Object.keys(prefilters) : [];
3005
- }, [selectedFilterLayer]);
3298
+ if (!selectedFilterLayer) return [];
3299
+ const prefilters = selectedFilterLayer.mapLayer.layerConfig?.prefilters;
3300
+ if (prefilters) {
3301
+ const keys = Object.keys(prefilters);
3302
+ if (keys.length > 0) return keys;
3303
+ }
3304
+ return catalogFieldsByLayer[String(selectedFilterLayer.mapLayer.layerId)] ?? [];
3305
+ }, [catalogFieldsByLayer, selectedFilterLayer]);
3006
3306
  const activeCatalogKey = selectedFilterLayer ? `${selectedFilterLayer.mapLayer.layerId}:${selectedFilterField}` : null;
3007
3307
  const activeCatalogValues = activeCatalogKey ? catalogByLayerField[activeCatalogKey] ?? [] : [];
3008
- const extractCatalogValues = React6.useCallback((catalogData, field) => {
3308
+ const extractCatalogValues = React7.useCallback((catalogData, field) => {
3009
3309
  const values = /* @__PURE__ */ new Set();
3010
3310
  const pushValue = (value) => {
3011
3311
  if (value === null || value === void 0) return;
@@ -3042,6 +3342,45 @@ var ZenitLayerManager = ({
3042
3342
  }
3043
3343
  return [...values].sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
3044
3344
  }, []);
3345
+ const extractCatalogFieldMap = React7.useCallback((catalogData, whitelist) => {
3346
+ if (!catalogData || typeof catalogData !== "object") return {};
3347
+ const maybeRecord = catalogData;
3348
+ const fieldNames = /* @__PURE__ */ new Set();
3349
+ Object.entries(maybeRecord).forEach(([key, value]) => {
3350
+ if (Array.isArray(value) && key !== "items" && key !== "features") {
3351
+ if (isFieldVisible(key)) fieldNames.add(key);
3352
+ }
3353
+ });
3354
+ const items = maybeRecord.items;
3355
+ if (Array.isArray(items)) {
3356
+ items.forEach((item) => {
3357
+ if (!item || typeof item !== "object") return;
3358
+ const row = item;
3359
+ if (row.field !== null && row.field !== void 0) {
3360
+ const fieldName = String(row.field).trim();
3361
+ if (fieldName && isFieldVisible(fieldName)) fieldNames.add(fieldName);
3362
+ }
3363
+ });
3364
+ }
3365
+ const features = maybeRecord.features;
3366
+ if (Array.isArray(features)) {
3367
+ features.forEach((feature) => {
3368
+ if (!feature || typeof feature !== "object") return;
3369
+ const properties = feature.properties;
3370
+ if (!properties || typeof properties !== "object") return;
3371
+ Object.keys(properties).forEach((key) => {
3372
+ if (isFieldVisible(key)) fieldNames.add(key);
3373
+ });
3374
+ });
3375
+ }
3376
+ const normalizedWhitelist = (whitelist ?? []).map((item) => String(item).trim()).filter(Boolean);
3377
+ const resolvedFieldNames = normalizedWhitelist.length > 0 ? [...fieldNames].filter((field) => matchesWhitelist(field, normalizedWhitelist)) : [...fieldNames];
3378
+ const next = {};
3379
+ resolvedFieldNames.forEach((field) => {
3380
+ next[field] = extractCatalogValues(catalogData, field);
3381
+ });
3382
+ return next;
3383
+ }, [extractCatalogValues]);
3045
3384
  useEffect6(() => {
3046
3385
  if (!filterableLayers.length) {
3047
3386
  setSelectedFilterLayerId("");
@@ -3068,17 +3407,35 @@ var ZenitLayerManager = ({
3068
3407
  }, [activeTab, hasPrefilters]);
3069
3408
  useEffect6(() => {
3070
3409
  if (activeTab !== "filters") return;
3071
- if (!selectedFilterLayer || !selectedFilterField || !activeCatalogKey) return;
3072
- if (catalogByLayerField[activeCatalogKey]) return;
3410
+ if (!selectedFilterLayer) return;
3411
+ const layerId = selectedFilterLayer.mapLayer.layerId;
3412
+ const layerKey = String(layerId);
3413
+ const prefilters = selectedFilterLayer.mapLayer.layerConfig?.prefilters;
3414
+ const requiresCatalogForFields = !prefilters || Object.keys(prefilters).length === 0;
3415
+ const hasFieldsLoaded = (catalogFieldsByLayer[layerKey]?.length ?? 0) > 0;
3416
+ const needsLayerCatalog = requiresCatalogForFields && !hasFieldsLoaded;
3417
+ const needsFieldCatalog = Boolean(activeCatalogKey && selectedFilterField && !catalogByLayerField[activeCatalogKey]);
3418
+ if (!needsLayerCatalog && !needsFieldCatalog) return;
3073
3419
  catalogAbortRef.current?.abort();
3074
3420
  const controller = new AbortController();
3075
3421
  catalogAbortRef.current = controller;
3076
3422
  setLoadingCatalog(true);
3077
3423
  setFilterError(null);
3078
- client.layers.getLayerFeaturesCatalog(selectedFilterLayer.mapLayer.layerId).then((response) => {
3424
+ client.layers.getLayerFeaturesCatalog(layerId).then((response) => {
3079
3425
  if (controller.signal.aborted) return;
3080
- const values = extractCatalogValues(response.data, selectedFilterField);
3081
- setCatalogByLayerField((prev) => ({ ...prev, [activeCatalogKey]: values }));
3426
+ const fieldMap = extractCatalogFieldMap(response.data, filterFieldWhitelist);
3427
+ const fields = Object.keys(fieldMap);
3428
+ setCatalogFieldsByLayer((prev) => ({ ...prev, [layerKey]: fields }));
3429
+ setCatalogByLayerField((prev) => {
3430
+ const next = { ...prev };
3431
+ fields.forEach((field) => {
3432
+ const key = `${layerKey}:${field}`;
3433
+ if (!next[key]) {
3434
+ next[key] = fieldMap[field] ?? [];
3435
+ }
3436
+ });
3437
+ return next;
3438
+ });
3082
3439
  }).catch((error) => {
3083
3440
  if (controller.signal.aborted) return;
3084
3441
  const message = error instanceof Error ? error.message : "No se pudo cargar el cat\xE1logo";
@@ -3089,8 +3446,8 @@ var ZenitLayerManager = ({
3089
3446
  return () => {
3090
3447
  controller.abort();
3091
3448
  };
3092
- }, [activeCatalogKey, activeTab, catalogByLayerField, client.layers, extractCatalogValues, selectedFilterField, selectedFilterLayer]);
3093
- const handleApplyFilter = React6.useCallback(async () => {
3449
+ }, [activeCatalogKey, activeTab, catalogByLayerField, catalogFieldsByLayer, client.layers, extractCatalogFieldMap, filterFieldWhitelist, selectedFilterField, selectedFilterLayer]);
3450
+ const handleApplyFilter = React7.useCallback(async () => {
3094
3451
  if (!selectedFilterLayer || !selectedFilterField || !selectedFilterValue || !onApplyLayerFilter) return;
3095
3452
  setApplyingFilter(true);
3096
3453
  setFilterError(null);
@@ -3112,7 +3469,7 @@ var ZenitLayerManager = ({
3112
3469
  setApplyingFilter(false);
3113
3470
  }
3114
3471
  }, [onApplyLayerFilter, selectedFilterField, selectedFilterLayer, selectedFilterValue]);
3115
- const handleClearFilter = React6.useCallback(async () => {
3472
+ const handleClearFilter = React7.useCallback(async () => {
3116
3473
  if (!selectedFilterLayer) return;
3117
3474
  setApplyingFilter(true);
3118
3475
  setFilterError(null);
@@ -3127,7 +3484,7 @@ var ZenitLayerManager = ({
3127
3484
  setApplyingFilter(false);
3128
3485
  }
3129
3486
  }, [onClearLayerFilter, selectedFilterField, selectedFilterLayer]);
3130
- const resolveLayerStyle = React6.useCallback(
3487
+ const resolveLayerStyle = React7.useCallback(
3131
3488
  (layerId) => {
3132
3489
  const layerKey = String(layerId);
3133
3490
  const fromProp = mapLayers?.find((entry) => String(entry.layerId) === layerKey)?.style;
@@ -3141,6 +3498,22 @@ var ZenitLayerManager = ({
3141
3498
  },
3142
3499
  [map, mapLayers]
3143
3500
  );
3501
+ const allVisible = decoratedLayers.every(
3502
+ (entry) => entry.effective?.visible ?? false
3503
+ );
3504
+ const anyVisible = decoratedLayers.some(
3505
+ (entry) => entry.effective?.visible ?? false
3506
+ );
3507
+ const handleToggleAllLayers = React7.useCallback(() => {
3508
+ if (!onLayerStatesChange) return;
3509
+ const nextVisible = !anyVisible;
3510
+ const next = effectiveStates.map((state) => ({
3511
+ ...state,
3512
+ visible: nextVisible,
3513
+ overrideVisible: nextVisible
3514
+ }));
3515
+ onLayerStatesChange(next);
3516
+ }, [anyVisible, effectiveStates, onLayerStatesChange]);
3144
3517
  const panelStyle = {
3145
3518
  width: 360,
3146
3519
  borderLeft: side === "right" ? "1px solid #e2e8f0" : void 0,
@@ -3157,10 +3530,10 @@ var ZenitLayerManager = ({
3157
3530
  ...height ? { height } : {}
3158
3531
  };
3159
3532
  if (loadingMap) {
3160
- return /* @__PURE__ */ jsx5("div", { className, style: panelStyle, children: "Cargando capas\u2026" });
3533
+ return /* @__PURE__ */ jsx6("div", { className, style: panelStyle, children: "Cargando capas\u2026" });
3161
3534
  }
3162
3535
  if (mapError) {
3163
- return /* @__PURE__ */ jsxs5("div", { className, style: { ...panelStyle, color: "#c53030" }, children: [
3536
+ return /* @__PURE__ */ jsxs6("div", { className, style: { ...panelStyle, color: "#c53030" }, children: [
3164
3537
  "Error al cargar mapa: ",
3165
3538
  mapError
3166
3539
  ] });
@@ -3178,7 +3551,7 @@ var ZenitLayerManager = ({
3178
3551
  boxShadow: "0 1px 0 rgba(148, 163, 184, 0.25)"
3179
3552
  };
3180
3553
  const renderLayerCards = () => {
3181
- return /* @__PURE__ */ jsx5("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: decoratedLayers.map((layerState) => {
3554
+ return /* @__PURE__ */ jsx6("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: decoratedLayers.map((layerState) => {
3182
3555
  const layerId = layerState.mapLayer.layerId;
3183
3556
  const layerName = layerState.layerName ?? `Capa ${layerId}`;
3184
3557
  const visible = layerState.effective?.visible ?? false;
@@ -3188,7 +3561,7 @@ var ZenitLayerManager = ({
3188
3561
  const muted = !visible;
3189
3562
  const opacityPercent = Math.round(userOpacity * 100);
3190
3563
  const sliderBackground = `linear-gradient(to right, ${layerColor} 0%, ${layerColor} ${opacityPercent}%, #e5e7eb ${opacityPercent}%, #e5e7eb 100%)`;
3191
- return /* @__PURE__ */ jsxs5(
3564
+ return /* @__PURE__ */ jsxs6(
3192
3565
  "div",
3193
3566
  {
3194
3567
  className: `zlm-card${muted ? " is-muted" : ""}`,
@@ -3203,9 +3576,9 @@ var ZenitLayerManager = ({
3203
3576
  width: "100%"
3204
3577
  },
3205
3578
  children: [
3206
- /* @__PURE__ */ jsxs5("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
3207
- /* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: 10, alignItems: "flex-start", minWidth: 0, flex: 1 }, children: [
3208
- /* @__PURE__ */ jsx5(
3579
+ /* @__PURE__ */ jsxs6("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
3580
+ /* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: 10, alignItems: "flex-start", minWidth: 0, flex: 1 }, children: [
3581
+ /* @__PURE__ */ jsx6(
3209
3582
  "div",
3210
3583
  {
3211
3584
  style: {
@@ -3220,7 +3593,7 @@ var ZenitLayerManager = ({
3220
3593
  title: "Color de la capa"
3221
3594
  }
3222
3595
  ),
3223
- showLayerVisibilityIcon && /* @__PURE__ */ jsx5(
3596
+ showLayerVisibilityIcon && /* @__PURE__ */ jsx6(
3224
3597
  "button",
3225
3598
  {
3226
3599
  type: "button",
@@ -3231,11 +3604,11 @@ var ZenitLayerManager = ({
3231
3604
  )
3232
3605
  ),
3233
3606
  "aria-label": visible ? "Ocultar capa" : "Mostrar capa",
3234
- children: visible ? /* @__PURE__ */ jsx5(Eye, { size: 16 }) : /* @__PURE__ */ jsx5(EyeOff, { size: 16 })
3607
+ children: visible ? /* @__PURE__ */ jsx6(Eye, { size: 16 }) : /* @__PURE__ */ jsx6(EyeOff, { size: 16 })
3235
3608
  }
3236
3609
  ),
3237
- /* @__PURE__ */ jsxs5("div", { style: { minWidth: 0, flex: 1 }, children: [
3238
- /* @__PURE__ */ jsx5(
3610
+ /* @__PURE__ */ jsxs6("div", { style: { minWidth: 0, flex: 1 }, children: [
3611
+ /* @__PURE__ */ jsx6(
3239
3612
  "div",
3240
3613
  {
3241
3614
  className: "zlm-layer-name",
@@ -3253,26 +3626,26 @@ var ZenitLayerManager = ({
3253
3626
  children: layerName
3254
3627
  }
3255
3628
  ),
3256
- /* @__PURE__ */ jsxs5("div", { style: { color: muted ? "#94a3b8" : "#64748b", fontSize: 12 }, children: [
3629
+ /* @__PURE__ */ jsxs6("div", { style: { color: muted ? "#94a3b8" : "#64748b", fontSize: 12 }, children: [
3257
3630
  "ID ",
3258
3631
  layerId
3259
3632
  ] })
3260
3633
  ] })
3261
3634
  ] }),
3262
- /* @__PURE__ */ jsx5("div", { style: { display: "flex", alignItems: "flex-start", gap: 6, flexShrink: 0 }, children: typeof featureCount === "number" && /* @__PURE__ */ jsxs5("span", { className: "zlm-badge", children: [
3635
+ /* @__PURE__ */ jsx6("div", { style: { display: "flex", alignItems: "flex-start", gap: 6, flexShrink: 0 }, children: typeof featureCount === "number" && /* @__PURE__ */ jsxs6("span", { className: "zlm-badge", children: [
3263
3636
  featureCount.toLocaleString(),
3264
3637
  " features"
3265
3638
  ] }) })
3266
3639
  ] }),
3267
- /* @__PURE__ */ jsx5("div", { style: { display: "flex", gap: 10, alignItems: "center" }, children: /* @__PURE__ */ jsxs5("div", { style: { flex: 1 }, children: [
3268
- /* @__PURE__ */ jsxs5("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 6, color: "#64748b", fontSize: 12 }, children: [
3269
- /* @__PURE__ */ jsx5("span", { children: "Opacidad" }),
3270
- /* @__PURE__ */ jsxs5("span", { children: [
3640
+ /* @__PURE__ */ jsx6("div", { style: { display: "flex", gap: 10, alignItems: "center" }, children: /* @__PURE__ */ jsxs6("div", { style: { flex: 1 }, children: [
3641
+ /* @__PURE__ */ jsxs6("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 6, color: "#64748b", fontSize: 12 }, children: [
3642
+ /* @__PURE__ */ jsx6("span", { children: "Opacidad" }),
3643
+ /* @__PURE__ */ jsxs6("span", { children: [
3271
3644
  opacityPercent,
3272
3645
  "%"
3273
3646
  ] })
3274
3647
  ] }),
3275
- /* @__PURE__ */ jsx5(
3648
+ /* @__PURE__ */ jsx6(
3276
3649
  "input",
3277
3650
  {
3278
3651
  className: "zlm-range",
@@ -3310,8 +3683,8 @@ var ZenitLayerManager = ({
3310
3683
  );
3311
3684
  }) });
3312
3685
  };
3313
- return /* @__PURE__ */ jsxs5("div", { className: ["zenit-layer-manager", className].filter(Boolean).join(" "), style: panelStyle, children: [
3314
- /* @__PURE__ */ jsx5("style", { children: `
3686
+ return /* @__PURE__ */ jsxs6("div", { className: ["zenit-layer-manager", className].filter(Boolean).join(" "), style: panelStyle, children: [
3687
+ /* @__PURE__ */ jsx6("style", { children: `
3315
3688
  .zenit-layer-manager .zlm-card {
3316
3689
  transition: box-shadow 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
3317
3690
  box-shadow: 0 6px 16px rgba(15, 23, 42, 0.08);
@@ -3406,16 +3779,16 @@ var ZenitLayerManager = ({
3406
3779
  outline-offset: 2px;
3407
3780
  }
3408
3781
  ` }),
3409
- /* @__PURE__ */ jsxs5("div", { style: headerStyle, children: [
3410
- /* @__PURE__ */ jsxs5("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
3411
- /* @__PURE__ */ jsxs5("div", { children: [
3412
- /* @__PURE__ */ jsx5("div", { style: { fontWeight: 800, fontSize: 16, color: "#0f172a" }, children: "Gesti\xF3n de Capas" }),
3413
- /* @__PURE__ */ jsxs5("div", { style: { color: "#64748b", fontSize: 12 }, children: [
3782
+ /* @__PURE__ */ jsxs6("div", { style: headerStyle, children: [
3783
+ /* @__PURE__ */ jsxs6("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
3784
+ /* @__PURE__ */ jsxs6("div", { children: [
3785
+ /* @__PURE__ */ jsx6("div", { style: { fontWeight: 800, fontSize: 16, color: "#0f172a" }, children: "Gesti\xF3n de Capas" }),
3786
+ /* @__PURE__ */ jsxs6("div", { style: { color: "#64748b", fontSize: 12 }, children: [
3414
3787
  "Mapa #",
3415
3788
  map.id
3416
3789
  ] })
3417
3790
  ] }),
3418
- /* @__PURE__ */ jsxs5(
3791
+ /* @__PURE__ */ jsxs6(
3419
3792
  "button",
3420
3793
  {
3421
3794
  type: "button",
@@ -3423,13 +3796,13 @@ var ZenitLayerManager = ({
3423
3796
  className: "zlm-panel-toggle",
3424
3797
  "aria-label": panelVisible ? "Ocultar panel de capas" : "Mostrar panel de capas",
3425
3798
  children: [
3426
- panelVisible ? /* @__PURE__ */ jsx5(Eye, { size: 16 }) : /* @__PURE__ */ jsx5(EyeOff, { size: 16 }),
3799
+ panelVisible ? /* @__PURE__ */ jsx6(Eye, { size: 16 }) : /* @__PURE__ */ jsx6(EyeOff, { size: 16 }),
3427
3800
  panelVisible ? "Ocultar" : "Mostrar"
3428
3801
  ]
3429
3802
  }
3430
3803
  )
3431
3804
  ] }),
3432
- /* @__PURE__ */ jsxs5(
3805
+ /* @__PURE__ */ jsxs6(
3433
3806
  "div",
3434
3807
  {
3435
3808
  style: {
@@ -3442,38 +3815,38 @@ var ZenitLayerManager = ({
3442
3815
  background: "#f1f5f9"
3443
3816
  },
3444
3817
  children: [
3445
- /* @__PURE__ */ jsxs5(
3818
+ /* @__PURE__ */ jsxs6(
3446
3819
  "button",
3447
3820
  {
3448
3821
  type: "button",
3449
3822
  className: `zlm-tab${activeTab === "layers" ? " is-active" : ""}`,
3450
3823
  onClick: () => setActiveTab("layers"),
3451
3824
  children: [
3452
- /* @__PURE__ */ jsx5(Layers, { size: 16 }),
3825
+ /* @__PURE__ */ jsx6(Layers, { size: 16 }),
3453
3826
  "Capas"
3454
3827
  ]
3455
3828
  }
3456
3829
  ),
3457
- showUploadTab && /* @__PURE__ */ jsxs5(
3830
+ showUploadTab && /* @__PURE__ */ jsxs6(
3458
3831
  "button",
3459
3832
  {
3460
3833
  type: "button",
3461
3834
  className: `zlm-tab${activeTab === "upload" ? " is-active" : ""}`,
3462
3835
  onClick: () => setActiveTab("upload"),
3463
3836
  children: [
3464
- /* @__PURE__ */ jsx5(Upload, { size: 16 }),
3837
+ /* @__PURE__ */ jsx6(Upload, { size: 16 }),
3465
3838
  "Subir"
3466
3839
  ]
3467
3840
  }
3468
3841
  ),
3469
- !hasPrefilters && /* @__PURE__ */ jsxs5(
3842
+ !hasPrefilters && /* @__PURE__ */ jsxs6(
3470
3843
  "button",
3471
3844
  {
3472
3845
  type: "button",
3473
3846
  className: `zlm-tab${activeTab === "filters" ? " is-active" : ""}`,
3474
3847
  onClick: () => setActiveTab("filters"),
3475
3848
  children: [
3476
- /* @__PURE__ */ jsx5(Layers, { size: 16 }),
3849
+ /* @__PURE__ */ jsx6(Layers, { size: 16 }),
3477
3850
  "Filtros"
3478
3851
  ]
3479
3852
  }
@@ -3482,13 +3855,29 @@ var ZenitLayerManager = ({
3482
3855
  }
3483
3856
  )
3484
3857
  ] }),
3485
- panelVisible && /* @__PURE__ */ jsxs5("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
3486
- hasPrefilters && /* @__PURE__ */ jsx5("div", { className: "zlm-badge", style: { marginBottom: 10 }, children: "Este mapa ya incluye filtros preaplicados" }),
3487
- activeTab === "layers" && renderLayerCards(),
3488
- !hasPrefilters && activeTab === "filters" && /* @__PURE__ */ jsx5("div", { className: "zlm-filter-panel", style: { display: "flex", flexDirection: "column", gap: 12, background: "#fff", border: "1px solid #e2e8f0", borderRadius: 12, padding: 12 }, children: !filterableLayers.length ? /* @__PURE__ */ jsx5("div", { style: { color: "#64748b", fontSize: 13 }, children: "No hay filtros disponibles para las capas de este mapa." }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
3489
- filterableLayers.length > 1 && /* @__PURE__ */ jsxs5("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
3858
+ panelVisible && /* @__PURE__ */ jsxs6("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
3859
+ hasPrefilters && /* @__PURE__ */ jsx6("div", { className: "zlm-badge", style: { marginBottom: 10 }, children: "Este mapa ya incluye filtros preaplicados" }),
3860
+ activeTab === "layers" && /* @__PURE__ */ jsxs6(Fragment3, { children: [
3861
+ /* @__PURE__ */ jsx6("div", { style: { marginBottom: 10 }, children: /* @__PURE__ */ jsxs6(
3862
+ "button",
3863
+ {
3864
+ type: "button",
3865
+ className: "zlm-panel-toggle",
3866
+ onClick: handleToggleAllLayers,
3867
+ disabled: decoratedLayers.length === 0,
3868
+ "aria-label": anyVisible ? "Ocultar todas las capas" : "Mostrar todas las capas",
3869
+ children: [
3870
+ anyVisible ? /* @__PURE__ */ jsx6(EyeOff, { size: 14 }) : /* @__PURE__ */ jsx6(Eye, { size: 14 }),
3871
+ anyVisible ? "Ocultar todas" : "Mostrar todas"
3872
+ ]
3873
+ }
3874
+ ) }),
3875
+ renderLayerCards()
3876
+ ] }),
3877
+ !hasPrefilters && activeTab === "filters" && /* @__PURE__ */ jsx6("div", { className: "zlm-filter-panel", style: { display: "flex", flexDirection: "column", gap: 12, background: "#fff", border: "1px solid #e2e8f0", borderRadius: 12, padding: 12 }, children: !filterableLayers.length ? /* @__PURE__ */ jsx6("div", { style: { color: "#64748b", fontSize: 13 }, children: "No hay filtros disponibles para las capas de este mapa." }) : /* @__PURE__ */ jsxs6(Fragment3, { children: [
3878
+ filterableLayers.length > 1 && /* @__PURE__ */ jsxs6("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
3490
3879
  "Capa",
3491
- /* @__PURE__ */ jsx5(
3880
+ /* @__PURE__ */ jsx6(
3492
3881
  ZenitSelect,
3493
3882
  {
3494
3883
  ariaLabel: "Seleccionar capa para filtrar",
@@ -3501,9 +3890,9 @@ var ZenitLayerManager = ({
3501
3890
  }
3502
3891
  )
3503
3892
  ] }),
3504
- /* @__PURE__ */ jsxs5("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
3893
+ /* @__PURE__ */ jsxs6("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
3505
3894
  "Campo",
3506
- /* @__PURE__ */ jsx5(
3895
+ /* @__PURE__ */ jsx6(
3507
3896
  ZenitSelect,
3508
3897
  {
3509
3898
  ariaLabel: "Seleccionar campo de filtrado",
@@ -3516,34 +3905,31 @@ var ZenitLayerManager = ({
3516
3905
  }
3517
3906
  )
3518
3907
  ] }),
3519
- /* @__PURE__ */ jsxs5("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
3908
+ /* @__PURE__ */ jsxs6("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
3520
3909
  "Valor",
3521
- /* @__PURE__ */ jsx5(
3522
- ZenitSelect,
3910
+ /* @__PURE__ */ jsx6(
3911
+ ZenitCombobox,
3523
3912
  {
3524
- ariaLabel: "Seleccionar valor de filtrado",
3525
3913
  value: selectedFilterValue,
3526
3914
  placeholder: "Seleccionar\u2026",
3527
- onValueChange: (nextValue) => setSelectedFilterValue(nextValue),
3528
- disabled: loadingCatalog || activeCatalogValues.length === 0,
3529
- options: activeCatalogValues.map((catalogValue) => ({
3530
- value: catalogValue,
3531
- label: catalogValue
3532
- }))
3915
+ searchPlaceholder: "Buscar valor\u2026",
3916
+ onChange: (nextValue) => setSelectedFilterValue(nextValue),
3917
+ options: activeCatalogValues,
3918
+ disabled: loadingCatalog || activeCatalogValues.length === 0
3533
3919
  }
3534
3920
  )
3535
3921
  ] }),
3536
- loadingCatalog && /* @__PURE__ */ jsx5("div", { style: { color: "#64748b", fontSize: 12 }, children: "Cargando cat\xE1logo\u2026" }),
3537
- !loadingCatalog && selectedFilterField && activeCatalogValues.length === 0 && /* @__PURE__ */ jsx5("div", { style: { color: "#64748b", fontSize: 12 }, children: "No hay cat\xE1logo disponible para este filtro." }),
3538
- filterError && /* @__PURE__ */ jsx5("div", { style: { color: "#b91c1c", fontSize: 12 }, children: filterError }),
3539
- appliedFilter && /* @__PURE__ */ jsxs5("div", { className: "zlm-badge", style: { alignSelf: "flex-start" }, children: [
3922
+ loadingCatalog && /* @__PURE__ */ jsx6("div", { style: { color: "#64748b", fontSize: 12 }, children: "Cargando cat\xE1logo\u2026" }),
3923
+ !loadingCatalog && selectedFilterField && activeCatalogValues.length === 0 && /* @__PURE__ */ jsx6("div", { style: { color: "#64748b", fontSize: 12 }, children: "No hay cat\xE1logo disponible para este filtro." }),
3924
+ filterError && /* @__PURE__ */ jsx6("div", { style: { color: "#b91c1c", fontSize: 12 }, children: filterError }),
3925
+ appliedFilter && /* @__PURE__ */ jsxs6("div", { className: "zlm-badge", style: { alignSelf: "flex-start" }, children: [
3540
3926
  "Activo: ",
3541
3927
  appliedFilter.field,
3542
3928
  " = ",
3543
3929
  appliedFilter.value
3544
3930
  ] }),
3545
- /* @__PURE__ */ jsxs5("div", { className: "zlm-filter-actions", style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
3546
- /* @__PURE__ */ jsx5(
3931
+ /* @__PURE__ */ jsxs6("div", { className: "zlm-filter-actions", style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
3932
+ /* @__PURE__ */ jsx6(
3547
3933
  "button",
3548
3934
  {
3549
3935
  type: "button",
@@ -3553,7 +3939,7 @@ var ZenitLayerManager = ({
3553
3939
  children: applyingFilter ? "Aplicando\u2026" : "Aplicar"
3554
3940
  }
3555
3941
  ),
3556
- /* @__PURE__ */ jsx5(
3942
+ /* @__PURE__ */ jsx6(
3557
3943
  "button",
3558
3944
  {
3559
3945
  type: "button",
@@ -3565,13 +3951,13 @@ var ZenitLayerManager = ({
3565
3951
  )
3566
3952
  ] })
3567
3953
  ] }) }),
3568
- showUploadTab && activeTab === "upload" && /* @__PURE__ */ jsx5("div", { style: { color: "#475569", fontSize: 13 }, children: "Pr\xF3ximamente podr\xE1s subir capas desde este panel." })
3954
+ showUploadTab && activeTab === "upload" && /* @__PURE__ */ jsx6("div", { style: { color: "#475569", fontSize: 13 }, children: "Pr\xF3ximamente podr\xE1s subir capas desde este panel." })
3569
3955
  ] })
3570
3956
  ] });
3571
3957
  };
3572
3958
 
3573
3959
  // src/react/ZenitFeatureFilterPanel.tsx
3574
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
3960
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
3575
3961
  var ZenitFeatureFilterPanel = ({
3576
3962
  title = "Filtros",
3577
3963
  description,
@@ -3579,7 +3965,7 @@ var ZenitFeatureFilterPanel = ({
3579
3965
  style,
3580
3966
  children
3581
3967
  }) => {
3582
- return /* @__PURE__ */ jsxs6(
3968
+ return /* @__PURE__ */ jsxs7(
3583
3969
  "section",
3584
3970
  {
3585
3971
  className,
@@ -3592,11 +3978,11 @@ var ZenitFeatureFilterPanel = ({
3592
3978
  ...style
3593
3979
  },
3594
3980
  children: [
3595
- /* @__PURE__ */ jsxs6("header", { style: { marginBottom: 12 }, children: [
3596
- /* @__PURE__ */ jsx6("h3", { style: { margin: 0, fontSize: 16 }, children: title }),
3597
- description && /* @__PURE__ */ jsx6("p", { style: { margin: "6px 0 0", color: "#475569", fontSize: 13 }, children: description })
3981
+ /* @__PURE__ */ jsxs7("header", { style: { marginBottom: 12 }, children: [
3982
+ /* @__PURE__ */ jsx7("h3", { style: { margin: 0, fontSize: 16 }, children: title }),
3983
+ description && /* @__PURE__ */ jsx7("p", { style: { margin: "6px 0 0", color: "#475569", fontSize: 13 }, children: description })
3598
3984
  ] }),
3599
- /* @__PURE__ */ jsx6("div", { children })
3985
+ /* @__PURE__ */ jsx7("div", { children })
3600
3986
  ]
3601
3987
  }
3602
3988
  );
@@ -3828,7 +4214,7 @@ var useSendMessageStream = (config) => {
3828
4214
  // src/react/components/MarkdownRenderer.tsx
3829
4215
  import ReactMarkdown from "react-markdown";
3830
4216
  import remarkGfm from "remark-gfm";
3831
- import { jsx as jsx7 } from "react/jsx-runtime";
4217
+ import { jsx as jsx8 } from "react/jsx-runtime";
3832
4218
  function normalizeAssistantMarkdown(text) {
3833
4219
  if (!text || typeof text !== "string") return "";
3834
4220
  let normalized = text;
@@ -3844,28 +4230,28 @@ var MarkdownRenderer = ({ content, className }) => {
3844
4230
  if (!normalizedContent) {
3845
4231
  return null;
3846
4232
  }
3847
- return /* @__PURE__ */ jsx7("div", { className, style: { wordBreak: "break-word" }, children: /* @__PURE__ */ jsx7(
4233
+ return /* @__PURE__ */ jsx8("div", { className, style: { wordBreak: "break-word" }, children: /* @__PURE__ */ jsx8(
3848
4234
  ReactMarkdown,
3849
4235
  {
3850
4236
  remarkPlugins: [remarkGfm],
3851
4237
  components: {
3852
4238
  // Headings with proper spacing
3853
- h1: ({ children, ...props }) => /* @__PURE__ */ jsx7("h1", { style: { fontSize: "1.5em", fontWeight: 700, marginTop: "1em", marginBottom: "0.5em" }, ...props, children }),
3854
- h2: ({ children, ...props }) => /* @__PURE__ */ jsx7("h2", { style: { fontSize: "1.3em", fontWeight: 700, marginTop: "0.9em", marginBottom: "0.45em" }, ...props, children }),
3855
- h3: ({ children, ...props }) => /* @__PURE__ */ jsx7("h3", { style: { fontSize: "1.15em", fontWeight: 600, marginTop: "0.75em", marginBottom: "0.4em" }, ...props, children }),
3856
- h4: ({ children, ...props }) => /* @__PURE__ */ jsx7("h4", { style: { fontSize: "1.05em", fontWeight: 600, marginTop: "0.6em", marginBottom: "0.35em" }, ...props, children }),
3857
- h5: ({ children, ...props }) => /* @__PURE__ */ jsx7("h5", { style: { fontSize: "1em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
3858
- h6: ({ children, ...props }) => /* @__PURE__ */ jsx7("h6", { style: { fontSize: "0.95em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
4239
+ h1: ({ children, ...props }) => /* @__PURE__ */ jsx8("h1", { style: { fontSize: "1.5em", fontWeight: 700, marginTop: "1em", marginBottom: "0.5em" }, ...props, children }),
4240
+ h2: ({ children, ...props }) => /* @__PURE__ */ jsx8("h2", { style: { fontSize: "1.3em", fontWeight: 700, marginTop: "0.9em", marginBottom: "0.45em" }, ...props, children }),
4241
+ h3: ({ children, ...props }) => /* @__PURE__ */ jsx8("h3", { style: { fontSize: "1.15em", fontWeight: 600, marginTop: "0.75em", marginBottom: "0.4em" }, ...props, children }),
4242
+ h4: ({ children, ...props }) => /* @__PURE__ */ jsx8("h4", { style: { fontSize: "1.05em", fontWeight: 600, marginTop: "0.6em", marginBottom: "0.35em" }, ...props, children }),
4243
+ h5: ({ children, ...props }) => /* @__PURE__ */ jsx8("h5", { style: { fontSize: "1em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
4244
+ h6: ({ children, ...props }) => /* @__PURE__ */ jsx8("h6", { style: { fontSize: "0.95em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
3859
4245
  // Paragraphs with comfortable line height
3860
- p: ({ children, ...props }) => /* @__PURE__ */ jsx7("p", { style: { marginTop: "0.5em", marginBottom: "0.5em", lineHeight: 1.6 }, ...props, children }),
4246
+ p: ({ children, ...props }) => /* @__PURE__ */ jsx8("p", { style: { marginTop: "0.5em", marginBottom: "0.5em", lineHeight: 1.6 }, ...props, children }),
3861
4247
  // Lists with proper indentation
3862
- ul: ({ children, ...props }) => /* @__PURE__ */ jsx7("ul", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
3863
- ol: ({ children, ...props }) => /* @__PURE__ */ jsx7("ol", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
3864
- li: ({ children, ...props }) => /* @__PURE__ */ jsx7("li", { style: { marginTop: "0.25em", marginBottom: "0.25em" }, ...props, children }),
4248
+ ul: ({ children, ...props }) => /* @__PURE__ */ jsx8("ul", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
4249
+ ol: ({ children, ...props }) => /* @__PURE__ */ jsx8("ol", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
4250
+ li: ({ children, ...props }) => /* @__PURE__ */ jsx8("li", { style: { marginTop: "0.25em", marginBottom: "0.25em" }, ...props, children }),
3865
4251
  // Code blocks
3866
4252
  code: ({ inline, children, ...props }) => {
3867
4253
  if (inline) {
3868
- return /* @__PURE__ */ jsx7(
4254
+ return /* @__PURE__ */ jsx8(
3869
4255
  "code",
3870
4256
  {
3871
4257
  style: {
@@ -3880,7 +4266,7 @@ var MarkdownRenderer = ({ content, className }) => {
3880
4266
  }
3881
4267
  );
3882
4268
  }
3883
- return /* @__PURE__ */ jsx7(
4269
+ return /* @__PURE__ */ jsx8(
3884
4270
  "code",
3885
4271
  {
3886
4272
  style: {
@@ -3900,9 +4286,9 @@ var MarkdownRenderer = ({ content, className }) => {
3900
4286
  );
3901
4287
  },
3902
4288
  // Pre (code block wrapper)
3903
- pre: ({ children, ...props }) => /* @__PURE__ */ jsx7("pre", { style: { margin: 0 }, ...props, children }),
4289
+ pre: ({ children, ...props }) => /* @__PURE__ */ jsx8("pre", { style: { margin: 0 }, ...props, children }),
3904
4290
  // Blockquotes
3905
- blockquote: ({ children, ...props }) => /* @__PURE__ */ jsx7(
4291
+ blockquote: ({ children, ...props }) => /* @__PURE__ */ jsx8(
3906
4292
  "blockquote",
3907
4293
  {
3908
4294
  style: {
@@ -3918,11 +4304,11 @@ var MarkdownRenderer = ({ content, className }) => {
3918
4304
  }
3919
4305
  ),
3920
4306
  // Strong/bold
3921
- strong: ({ children, ...props }) => /* @__PURE__ */ jsx7("strong", { style: { fontWeight: 600 }, ...props, children }),
4307
+ strong: ({ children, ...props }) => /* @__PURE__ */ jsx8("strong", { style: { fontWeight: 600 }, ...props, children }),
3922
4308
  // Emphasis/italic
3923
- em: ({ children, ...props }) => /* @__PURE__ */ jsx7("em", { style: { fontStyle: "italic" }, ...props, children }),
4309
+ em: ({ children, ...props }) => /* @__PURE__ */ jsx8("em", { style: { fontStyle: "italic" }, ...props, children }),
3924
4310
  // Horizontal rule
3925
- hr: (props) => /* @__PURE__ */ jsx7(
4311
+ hr: (props) => /* @__PURE__ */ jsx8(
3926
4312
  "hr",
3927
4313
  {
3928
4314
  style: {
@@ -3935,7 +4321,7 @@ var MarkdownRenderer = ({ content, className }) => {
3935
4321
  }
3936
4322
  ),
3937
4323
  // Tables (GFM)
3938
- table: ({ children, ...props }) => /* @__PURE__ */ jsx7("div", { style: { overflowX: "auto", marginTop: "0.5em", marginBottom: "0.5em" }, children: /* @__PURE__ */ jsx7(
4324
+ table: ({ children, ...props }) => /* @__PURE__ */ jsx8("div", { style: { overflowX: "auto", marginTop: "0.5em", marginBottom: "0.5em" }, children: /* @__PURE__ */ jsx8(
3939
4325
  "table",
3940
4326
  {
3941
4327
  style: {
@@ -3947,7 +4333,7 @@ var MarkdownRenderer = ({ content, className }) => {
3947
4333
  children
3948
4334
  }
3949
4335
  ) }),
3950
- th: ({ children, ...props }) => /* @__PURE__ */ jsx7(
4336
+ th: ({ children, ...props }) => /* @__PURE__ */ jsx8(
3951
4337
  "th",
3952
4338
  {
3953
4339
  style: {
@@ -3961,7 +4347,7 @@ var MarkdownRenderer = ({ content, className }) => {
3961
4347
  children
3962
4348
  }
3963
4349
  ),
3964
- td: ({ children, ...props }) => /* @__PURE__ */ jsx7(
4350
+ td: ({ children, ...props }) => /* @__PURE__ */ jsx8(
3965
4351
  "td",
3966
4352
  {
3967
4353
  style: {
@@ -3979,32 +4365,32 @@ var MarkdownRenderer = ({ content, className }) => {
3979
4365
  };
3980
4366
 
3981
4367
  // src/react/ai/FloatingChatBox.tsx
3982
- import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
3983
- var ChatIcon = () => /* @__PURE__ */ jsx8("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx8("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
3984
- var CloseIcon = () => /* @__PURE__ */ jsxs7("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3985
- /* @__PURE__ */ jsx8("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
3986
- /* @__PURE__ */ jsx8("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
4368
+ import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
4369
+ var ChatIcon = () => /* @__PURE__ */ jsx9("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx9("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
4370
+ var CloseIcon = () => /* @__PURE__ */ jsxs8("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4371
+ /* @__PURE__ */ jsx9("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
4372
+ /* @__PURE__ */ jsx9("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
3987
4373
  ] });
3988
- var ExpandIcon = () => /* @__PURE__ */ jsxs7("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3989
- /* @__PURE__ */ jsx8("polyline", { points: "15 3 21 3 21 9" }),
3990
- /* @__PURE__ */ jsx8("polyline", { points: "9 21 3 21 3 15" }),
3991
- /* @__PURE__ */ jsx8("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
3992
- /* @__PURE__ */ jsx8("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
4374
+ var ExpandIcon = () => /* @__PURE__ */ jsxs8("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4375
+ /* @__PURE__ */ jsx9("polyline", { points: "15 3 21 3 21 9" }),
4376
+ /* @__PURE__ */ jsx9("polyline", { points: "9 21 3 21 3 15" }),
4377
+ /* @__PURE__ */ jsx9("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
4378
+ /* @__PURE__ */ jsx9("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
3993
4379
  ] });
3994
- var CollapseIcon = () => /* @__PURE__ */ jsxs7("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3995
- /* @__PURE__ */ jsx8("polyline", { points: "4 14 10 14 10 20" }),
3996
- /* @__PURE__ */ jsx8("polyline", { points: "20 10 14 10 14 4" }),
3997
- /* @__PURE__ */ jsx8("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
3998
- /* @__PURE__ */ jsx8("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
4380
+ var CollapseIcon = () => /* @__PURE__ */ jsxs8("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4381
+ /* @__PURE__ */ jsx9("polyline", { points: "4 14 10 14 10 20" }),
4382
+ /* @__PURE__ */ jsx9("polyline", { points: "20 10 14 10 14 4" }),
4383
+ /* @__PURE__ */ jsx9("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
4384
+ /* @__PURE__ */ jsx9("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
3999
4385
  ] });
4000
- var SendIcon = () => /* @__PURE__ */ jsxs7("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4001
- /* @__PURE__ */ jsx8("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
4002
- /* @__PURE__ */ jsx8("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
4386
+ var SendIcon = () => /* @__PURE__ */ jsxs8("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4387
+ /* @__PURE__ */ jsx9("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
4388
+ /* @__PURE__ */ jsx9("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
4003
4389
  ] });
4004
- var LayersIcon = () => /* @__PURE__ */ jsxs7("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4005
- /* @__PURE__ */ jsx8("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
4006
- /* @__PURE__ */ jsx8("polyline", { points: "2 17 12 22 22 17" }),
4007
- /* @__PURE__ */ jsx8("polyline", { points: "2 12 12 17 22 12" })
4390
+ var LayersIcon = () => /* @__PURE__ */ jsxs8("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4391
+ /* @__PURE__ */ jsx9("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
4392
+ /* @__PURE__ */ jsx9("polyline", { points: "2 17 12 22 22 17" }),
4393
+ /* @__PURE__ */ jsx9("polyline", { points: "2 12 12 17 22 12" })
4008
4394
  ] });
4009
4395
  var styles = {
4010
4396
  root: {
@@ -4471,13 +4857,13 @@ var FloatingChatBox = ({
4471
4857
  if (!response?.metadata) return null;
4472
4858
  const referencedLayers = response.metadata.referencedLayers;
4473
4859
  if (!referencedLayers || referencedLayers.length === 0) return null;
4474
- return /* @__PURE__ */ jsxs7("div", { style: styles.metadataSection, children: [
4475
- /* @__PURE__ */ jsxs7("div", { style: styles.metadataTitle, children: [
4476
- /* @__PURE__ */ jsx8(LayersIcon, {}),
4860
+ return /* @__PURE__ */ jsxs8("div", { style: styles.metadataSection, children: [
4861
+ /* @__PURE__ */ jsxs8("div", { style: styles.metadataTitle, children: [
4862
+ /* @__PURE__ */ jsx9(LayersIcon, {}),
4477
4863
  "Capas Analizadas"
4478
4864
  ] }),
4479
- /* @__PURE__ */ jsx8("ul", { style: styles.metadataList, children: referencedLayers.map((layer, index) => /* @__PURE__ */ jsxs7("li", { style: styles.metadataItem, children: [
4480
- /* @__PURE__ */ jsx8("strong", { children: layer.layerName }),
4865
+ /* @__PURE__ */ jsx9("ul", { style: styles.metadataList, children: referencedLayers.map((layer, index) => /* @__PURE__ */ jsxs8("li", { style: styles.metadataItem, children: [
4866
+ /* @__PURE__ */ jsx9("strong", { children: layer.layerName }),
4481
4867
  " (",
4482
4868
  layer.featureCount,
4483
4869
  " ",
@@ -4495,9 +4881,9 @@ var FloatingChatBox = ({
4495
4881
  }, [isStreaming, setOpen, onActionClick]);
4496
4882
  const renderActions = (response) => {
4497
4883
  if (!response?.suggestedActions?.length) return null;
4498
- return /* @__PURE__ */ jsxs7("div", { style: styles.actionsSection, children: [
4499
- /* @__PURE__ */ jsx8("div", { style: styles.sectionLabel, children: "Acciones Sugeridas" }),
4500
- /* @__PURE__ */ jsx8("div", { style: styles.actionsGrid, children: response.suggestedActions.map((action, index) => /* @__PURE__ */ jsx8(
4884
+ return /* @__PURE__ */ jsxs8("div", { style: styles.actionsSection, children: [
4885
+ /* @__PURE__ */ jsx9("div", { style: styles.sectionLabel, children: "Acciones Sugeridas" }),
4886
+ /* @__PURE__ */ jsx9("div", { style: styles.actionsGrid, children: response.suggestedActions.map((action, index) => /* @__PURE__ */ jsx9(
4501
4887
  "button",
4502
4888
  {
4503
4889
  type: "button",
@@ -4528,9 +4914,9 @@ var FloatingChatBox = ({
4528
4914
  };
4529
4915
  const renderFollowUps = (response) => {
4530
4916
  if (!response?.followUpQuestions?.length) return null;
4531
- return /* @__PURE__ */ jsxs7("div", { style: styles.actionsSection, children: [
4532
- /* @__PURE__ */ jsx8("div", { style: styles.sectionLabel, children: "Preguntas Relacionadas" }),
4533
- /* @__PURE__ */ jsx8("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: response.followUpQuestions.map((question, index) => /* @__PURE__ */ jsx8(
4917
+ return /* @__PURE__ */ jsxs8("div", { style: styles.actionsSection, children: [
4918
+ /* @__PURE__ */ jsx9("div", { style: styles.sectionLabel, children: "Preguntas Relacionadas" }),
4919
+ /* @__PURE__ */ jsx9("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: response.followUpQuestions.map((question, index) => /* @__PURE__ */ jsx9(
4534
4920
  "button",
4535
4921
  {
4536
4922
  type: "button",
@@ -4559,8 +4945,8 @@ var FloatingChatBox = ({
4559
4945
  )) })
4560
4946
  ] });
4561
4947
  };
4562
- const chatContent = /* @__PURE__ */ jsxs7("div", { style: styles.root, children: [
4563
- /* @__PURE__ */ jsx8("style", { children: `
4948
+ const chatContent = /* @__PURE__ */ jsxs8("div", { style: styles.root, children: [
4949
+ /* @__PURE__ */ jsx9("style", { children: `
4564
4950
  @keyframes zenitBlink {
4565
4951
  0%, 49% { opacity: 1; }
4566
4952
  50%, 100% { opacity: 0; }
@@ -4616,7 +5002,7 @@ var FloatingChatBox = ({
4616
5002
  }
4617
5003
  }
4618
5004
  ` }),
4619
- open && /* @__PURE__ */ jsxs7(
5005
+ open && /* @__PURE__ */ jsxs8(
4620
5006
  "div",
4621
5007
  {
4622
5008
  ref: chatBoxRef,
@@ -4630,10 +5016,10 @@ var FloatingChatBox = ({
4630
5016
  };
4631
5017
  })(),
4632
5018
  children: [
4633
- /* @__PURE__ */ jsxs7("header", { style: styles.header, children: [
4634
- /* @__PURE__ */ jsx8("h3", { style: styles.title, children: "Asistente Zenit AI" }),
4635
- /* @__PURE__ */ jsxs7("div", { style: styles.headerButtons, children: [
4636
- !isMobile && /* @__PURE__ */ jsx8(
5019
+ /* @__PURE__ */ jsxs8("header", { style: styles.header, children: [
5020
+ /* @__PURE__ */ jsx9("h3", { style: styles.title, children: "Asistente Zenit AI" }),
5021
+ /* @__PURE__ */ jsxs8("div", { style: styles.headerButtons, children: [
5022
+ !isMobile && /* @__PURE__ */ jsx9(
4637
5023
  "button",
4638
5024
  {
4639
5025
  type: "button",
@@ -4646,10 +5032,10 @@ var FloatingChatBox = ({
4646
5032
  e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
4647
5033
  },
4648
5034
  "aria-label": expanded ? "Contraer" : "Expandir",
4649
- children: expanded ? /* @__PURE__ */ jsx8(CollapseIcon, {}) : /* @__PURE__ */ jsx8(ExpandIcon, {})
5035
+ children: expanded ? /* @__PURE__ */ jsx9(CollapseIcon, {}) : /* @__PURE__ */ jsx9(ExpandIcon, {})
4650
5036
  }
4651
5037
  ),
4652
- /* @__PURE__ */ jsx8(
5038
+ /* @__PURE__ */ jsx9(
4653
5039
  "button",
4654
5040
  {
4655
5041
  type: "button",
@@ -4662,20 +5048,20 @@ var FloatingChatBox = ({
4662
5048
  e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
4663
5049
  },
4664
5050
  "aria-label": "Cerrar",
4665
- children: /* @__PURE__ */ jsx8(CloseIcon, {})
5051
+ children: /* @__PURE__ */ jsx9(CloseIcon, {})
4666
5052
  }
4667
5053
  )
4668
5054
  ] })
4669
5055
  ] }),
4670
- /* @__PURE__ */ jsxs7("div", { ref: messagesContainerRef, className: "zenit-ai-body", style: styles.messages, children: [
4671
- messages.map((message) => /* @__PURE__ */ jsx8(
5056
+ /* @__PURE__ */ jsxs8("div", { ref: messagesContainerRef, className: "zenit-ai-body", style: styles.messages, children: [
5057
+ messages.map((message) => /* @__PURE__ */ jsx9(
4672
5058
  "div",
4673
5059
  {
4674
5060
  style: {
4675
5061
  ...styles.messageWrapper,
4676
5062
  alignItems: message.role === "user" ? "flex-end" : "flex-start"
4677
5063
  },
4678
- children: /* @__PURE__ */ jsxs7(
5064
+ children: /* @__PURE__ */ jsxs8(
4679
5065
  "div",
4680
5066
  {
4681
5067
  style: {
@@ -4683,7 +5069,7 @@ var FloatingChatBox = ({
4683
5069
  ...message.role === "user" ? styles.userMessage : styles.assistantMessage
4684
5070
  },
4685
5071
  children: [
4686
- message.role === "assistant" ? /* @__PURE__ */ jsx8(MarkdownRenderer, { content: message.content }) : message.content,
5072
+ message.role === "assistant" ? /* @__PURE__ */ jsx9(MarkdownRenderer, { content: message.content }) : message.content,
4687
5073
  message.role === "assistant" && renderMetadata(message.response),
4688
5074
  message.role === "assistant" && renderActions(message.response),
4689
5075
  message.role === "assistant" && renderFollowUps(message.response)
@@ -4693,39 +5079,39 @@ var FloatingChatBox = ({
4693
5079
  },
4694
5080
  message.id
4695
5081
  )),
4696
- isStreaming && /* @__PURE__ */ jsx8(
5082
+ isStreaming && /* @__PURE__ */ jsx9(
4697
5083
  "div",
4698
5084
  {
4699
5085
  style: {
4700
5086
  ...styles.messageWrapper,
4701
5087
  alignItems: "flex-start"
4702
5088
  },
4703
- children: /* @__PURE__ */ jsx8(
5089
+ children: /* @__PURE__ */ jsx9(
4704
5090
  "div",
4705
5091
  {
4706
5092
  style: {
4707
5093
  ...styles.messageBubble,
4708
5094
  ...styles.assistantMessage
4709
5095
  },
4710
- children: streamingText ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
4711
- /* @__PURE__ */ jsx8(MarkdownRenderer, { content: streamingText }),
4712
- /* @__PURE__ */ jsx8("span", { style: styles.cursor })
4713
- ] }) : /* @__PURE__ */ jsxs7("div", { style: styles.thinkingText, children: [
4714
- /* @__PURE__ */ jsx8("span", { children: "Pensando" }),
4715
- /* @__PURE__ */ jsxs7("div", { style: styles.typingIndicator, children: [
4716
- /* @__PURE__ */ jsx8("div", { className: "zenit-typing-dot", style: styles.typingDot }),
4717
- /* @__PURE__ */ jsx8("div", { className: "zenit-typing-dot", style: styles.typingDot }),
4718
- /* @__PURE__ */ jsx8("div", { className: "zenit-typing-dot", style: styles.typingDot })
5096
+ children: streamingText ? /* @__PURE__ */ jsxs8(Fragment4, { children: [
5097
+ /* @__PURE__ */ jsx9(MarkdownRenderer, { content: streamingText }),
5098
+ /* @__PURE__ */ jsx9("span", { style: styles.cursor })
5099
+ ] }) : /* @__PURE__ */ jsxs8("div", { style: styles.thinkingText, children: [
5100
+ /* @__PURE__ */ jsx9("span", { children: "Pensando" }),
5101
+ /* @__PURE__ */ jsxs8("div", { style: styles.typingIndicator, children: [
5102
+ /* @__PURE__ */ jsx9("div", { className: "zenit-typing-dot", style: styles.typingDot }),
5103
+ /* @__PURE__ */ jsx9("div", { className: "zenit-typing-dot", style: styles.typingDot }),
5104
+ /* @__PURE__ */ jsx9("div", { className: "zenit-typing-dot", style: styles.typingDot })
4719
5105
  ] })
4720
5106
  ] })
4721
5107
  }
4722
5108
  )
4723
5109
  }
4724
5110
  ),
4725
- /* @__PURE__ */ jsx8("div", { ref: messagesEndRef })
5111
+ /* @__PURE__ */ jsx9("div", { ref: messagesEndRef })
4726
5112
  ] }),
4727
- /* @__PURE__ */ jsxs7("div", { className: "zenit-ai-input-area", style: styles.inputWrapper, children: [
4728
- /* @__PURE__ */ jsx8(
5113
+ /* @__PURE__ */ jsxs8("div", { className: "zenit-ai-input-area", style: styles.inputWrapper, children: [
5114
+ /* @__PURE__ */ jsx9(
4729
5115
  "textarea",
4730
5116
  {
4731
5117
  style: {
@@ -4742,7 +5128,7 @@ var FloatingChatBox = ({
4742
5128
  disabled: !mapId || !baseUrl || isStreaming
4743
5129
  }
4744
5130
  ),
4745
- /* @__PURE__ */ jsx8(
5131
+ /* @__PURE__ */ jsx9(
4746
5132
  "button",
4747
5133
  {
4748
5134
  type: "button",
@@ -4751,18 +5137,18 @@ var FloatingChatBox = ({
4751
5137
  onClick: () => void handleSend(),
4752
5138
  disabled: !canSend,
4753
5139
  "aria-label": "Enviar mensaje",
4754
- children: /* @__PURE__ */ jsx8(SendIcon, {})
5140
+ children: /* @__PURE__ */ jsx9(SendIcon, {})
4755
5141
  }
4756
5142
  )
4757
5143
  ] }),
4758
- errorMessage && /* @__PURE__ */ jsx8("div", { style: styles.errorText, children: errorMessage }),
4759
- isStreaming && !errorMessage && /* @__PURE__ */ jsx8("div", { style: styles.statusNote, children: "Generando sugerencias..." }),
4760
- !mapId && !errorMessage && /* @__PURE__ */ jsx8("div", { style: styles.statusNote, children: "Selecciona un mapa para usar el asistente" }),
4761
- !baseUrl && !errorMessage && /* @__PURE__ */ jsx8("div", { style: styles.statusNote, children: "Configura la baseUrl del SDK" })
5144
+ errorMessage && /* @__PURE__ */ jsx9("div", { style: styles.errorText, children: errorMessage }),
5145
+ isStreaming && !errorMessage && /* @__PURE__ */ jsx9("div", { style: styles.statusNote, children: "Generando sugerencias..." }),
5146
+ !mapId && !errorMessage && /* @__PURE__ */ jsx9("div", { style: styles.statusNote, children: "Selecciona un mapa para usar el asistente" }),
5147
+ !baseUrl && !errorMessage && /* @__PURE__ */ jsx9("div", { style: styles.statusNote, children: "Configura la baseUrl del SDK" })
4762
5148
  ]
4763
5149
  }
4764
5150
  ),
4765
- !(hideButton && !open) && /* @__PURE__ */ jsx8(
5151
+ !(hideButton && !open) && /* @__PURE__ */ jsx9(
4766
5152
  "button",
4767
5153
  {
4768
5154
  type: "button",
@@ -4774,9 +5160,9 @@ var FloatingChatBox = ({
4774
5160
  },
4775
5161
  onClick: () => setOpen((prev) => !prev),
4776
5162
  "aria-label": open ? "Cerrar asistente" : "Abrir asistente Zenit AI",
4777
- children: open ? /* @__PURE__ */ jsx8(CloseIcon, {}) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
4778
- /* @__PURE__ */ jsx8(ChatIcon, {}),
4779
- !isMobile && /* @__PURE__ */ jsx8("span", { children: "Asistente IA" })
5163
+ children: open ? /* @__PURE__ */ jsx9(CloseIcon, {}) : /* @__PURE__ */ jsxs8(Fragment4, { children: [
5164
+ /* @__PURE__ */ jsx9(ChatIcon, {}),
5165
+ !isMobile && /* @__PURE__ */ jsx9("span", { children: "Asistente IA" })
4780
5166
  ] })
4781
5167
  }
4782
5168
  )
@@ -4827,4 +5213,4 @@ export {
4827
5213
  useSendMessageStream,
4828
5214
  FloatingChatBox
4829
5215
  };
4830
- //# sourceMappingURL=chunk-J2YWF2TS.mjs.map
5216
+ //# sourceMappingURL=chunk-3M57OBM6.mjs.map