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.
@@ -505,6 +505,14 @@ var LayerGeoJson = ({
505
505
  onEachFeature,
506
506
  onPolygonLabel
507
507
  }) => {
508
+ const styleFnRef = (0, import_react.useRef)(styleFn);
509
+ const onEachFeatureRef = (0, import_react.useRef)(onEachFeature);
510
+ (0, import_react.useEffect)(() => {
511
+ styleFnRef.current = styleFn;
512
+ }, [styleFn]);
513
+ (0, import_react.useEffect)(() => {
514
+ onEachFeatureRef.current = onEachFeature;
515
+ }, [onEachFeature]);
508
516
  const safeData = (0, import_react.useMemo)(() => sanitizeGeoJson(data, String(layerId)), [data, layerId]);
509
517
  const features = (0, import_react.useMemo)(() => safeData.features ?? [], [safeData]);
510
518
  const fillFeatures = (0, import_react.useMemo)(() => features.filter(isNonPointGeometry), [features]);
@@ -548,14 +556,14 @@ var LayerGeoJson = ({
548
556
  if (!isValidLatLng(latlng)) {
549
557
  return createInvisibleFallbackClusterMarker();
550
558
  }
551
- const style = styleFn(feature, layerType, baseOpacity);
559
+ const style = styleFnRef.current(feature, layerType, baseOpacity);
552
560
  return import_leaflet.default.marker(latlng, {
553
561
  icon: createPointDivIcon(style, isMobile),
554
562
  pane: clusterPaneName,
555
563
  interactive: true
556
564
  });
557
565
  },
558
- onEachFeature
566
+ onEachFeature: (feature, layer) => onEachFeatureRef.current(feature, layer)
559
567
  });
560
568
  clusterLayer.addLayer(geoJsonLayer);
561
569
  return () => {
@@ -570,11 +578,9 @@ var LayerGeoJson = ({
570
578
  isMobile,
571
579
  layerType,
572
580
  mapInstance,
573
- onEachFeature,
574
581
  panesReady,
575
582
  pointsData,
576
- resolvedPointsPane,
577
- styleFn
583
+ resolvedPointsPane
578
584
  ]);
579
585
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
580
586
  fillData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -683,6 +689,55 @@ function useGeolocation(options) {
683
689
 
684
690
  // src/react/map/map-utils.ts
685
691
  var import_leaflet2 = __toESM(require("leaflet"));
692
+
693
+ // src/config/modalWhitelist.ts
694
+ var SECTOR_MODAL_WHITELIST = [
695
+ { key: "Sector", label: "Sector" },
696
+ { key: "Promotor", label: "Promotor" },
697
+ { key: "Capital Total", label: "Capital Total" },
698
+ { key: "Total Capital Mora", label: "Capital en Mora" },
699
+ { key: "Tendencia Mora", label: "Tendencia de Mora", hint: "trend_icon" },
700
+ { key: "Tendencia Capital", label: "Tendencia de Capital", hint: "trend_icon" },
701
+ { key: "Tendencia Castigos", label: "Tendencia de Castigos", hint: "trend_icon" },
702
+ { key: "Impacto Sector", label: "Impacto del Sector" },
703
+ { key: "Total Clientes Sector", label: "Total de Clientes" },
704
+ { key: "Total Clientes Sanos", label: "Clientes Sanos" },
705
+ { key: "Total Clientes Morosos", label: "Clientes en Mora" },
706
+ { key: "Total Clientes Castigados", label: "Clientes Castigados" },
707
+ { key: "Total Clientes Nuevos", label: "Clientes Nuevos" },
708
+ { key: "Total Clientes Salidos", label: "Clientes Salidos" },
709
+ { key: "Insights", label: "An\xE1lisis IA", hint: "collapsible" },
710
+ { key: "Recomendaciones", label: "Recomendaciones IA", hint: "collapsible" }
711
+ ];
712
+ var CLIENTE_MODAL_WHITELIST = [
713
+ { key: "nombre del cliente", label: "Nombre del Cliente" },
714
+ { key: "dpi", label: "DPI" },
715
+ { key: "kpi", label: "Estado", hint: "kpi_badge" },
716
+ { key: "tel principal", label: "Tel\xE9fono", hint: "phone_link" },
717
+ { key: "capital concedido", label: "Capital Concedido" },
718
+ { key: "mora", label: "Monto en Mora", hint: "mora_alert" },
719
+ { key: "etapa", label: "Etapa del Cr\xE9dito" },
720
+ { key: "prestamo", label: "No. de Pr\xE9stamo" },
721
+ { key: "sucursal", label: "Sucursal", aliases: ["nombre sucursal"] }
722
+ ];
723
+ function applyModalWhitelist(rawData, whitelist) {
724
+ const keys = Object.keys(rawData ?? {});
725
+ return whitelist.map(({ key, label, hint, aliases = [] }) => {
726
+ const keysToTry = [key, ...aliases];
727
+ let value = void 0;
728
+ for (const k of keysToTry) {
729
+ const match = keys.find((rawKey) => rawKey.toLowerCase() === k.toLowerCase());
730
+ if (match !== void 0 && rawData[match] !== null && rawData[match] !== void 0) {
731
+ value = rawData[match];
732
+ break;
733
+ }
734
+ }
735
+ if (value === void 0) return null;
736
+ return { label, value, hint: hint ?? null };
737
+ }).filter((entry) => Boolean(entry));
738
+ }
739
+
740
+ // src/react/map/map-utils.ts
686
741
  var POPUP_STYLE_ID = "zenit-leaflet-popup-styles";
687
742
  var POPUP_EXCLUDED_KEYS = /* @__PURE__ */ new Set(["geom", "geometry", "_private"]);
688
743
  var POPUP_TITLE_KEYS = ["id", "nombre", "name", "title", "titulo", "cluster"];
@@ -919,6 +974,10 @@ function shouldIncludePopupEntry(key, value) {
919
974
  return true;
920
975
  }
921
976
  function createPopupContent(properties) {
977
+ const whitelistedRows = buildWhitelistedRows(properties);
978
+ if (whitelistedRows) {
979
+ return whitelistedRows;
980
+ }
922
981
  const header = findHeaderProperties(properties);
923
982
  const headerText = header.title?.value ?? extractPopupHeader(properties);
924
983
  const usedKeys = new Set([header.title?.key, header.badge?.key, header.description?.key].filter(Boolean));
@@ -958,6 +1017,37 @@ function createPopupContent(properties) {
958
1017
  }).join("");
959
1018
  return `<div>${colorBar}${headerHtml}${descriptionHtml}${rowsHtml}</div>`;
960
1019
  }
1020
+ function buildWhitelistedRows(properties) {
1021
+ const whitelist = selectModalWhitelist(properties);
1022
+ if (!whitelist) return null;
1023
+ const entries = applyModalWhitelist(properties, whitelist);
1024
+ if (entries.length === 0) {
1025
+ return '<div style="padding:8px 0; color:#64748b; text-align:center;">Sin datos disponibles</div>';
1026
+ }
1027
+ const rowsHtml = entries.map(({ label, value }) => {
1028
+ const valueHtml = renderPopupValue(value);
1029
+ return `
1030
+ <div style="display:grid; grid-template-columns:minmax(90px, 35%) 1fr; gap:8px; padding:6px 0; border-bottom:1px solid #e2e8f0;">
1031
+ <div style="font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.04em; color:#64748b;">${escapeHtml(label)}</div>
1032
+ <div style="font-size:13px; color:#0f172a; word-break:break-word;">${valueHtml}</div>
1033
+ </div>
1034
+ `;
1035
+ }).join("");
1036
+ return `<div>${rowsHtml}</div>`;
1037
+ }
1038
+ function countWhitelistMatches(properties, whitelist) {
1039
+ const keys = Object.keys(properties).map((key) => key.toLowerCase());
1040
+ return whitelist.reduce((count, item) => {
1041
+ const candidates = [item.key, ...item.aliases ?? []].map((candidate) => candidate.toLowerCase());
1042
+ return candidates.some((candidate) => keys.includes(candidate)) ? count + 1 : count;
1043
+ }, 0);
1044
+ }
1045
+ function selectModalWhitelist(properties) {
1046
+ const sectorMatches = countWhitelistMatches(properties, SECTOR_MODAL_WHITELIST);
1047
+ const clienteMatches = countWhitelistMatches(properties, CLIENTE_MODAL_WHITELIST);
1048
+ if (sectorMatches === 0 && clienteMatches === 0) return null;
1049
+ return sectorMatches >= clienteMatches ? SECTOR_MODAL_WHITELIST : CLIENTE_MODAL_WHITELIST;
1050
+ }
961
1051
  function isPolygonType(layerType, geometryType) {
962
1052
  const candidate = (layerType ?? geometryType ?? "").toLowerCase();
963
1053
  return candidate === "polygon" || candidate === "multipolygon";
@@ -1486,6 +1576,14 @@ function pickIntersectFeature(params) {
1486
1576
  selectedIdx: candidates.findIndex((candidate) => candidate === feature),
1487
1577
  reason
1488
1578
  });
1579
+ if (clickIntent === "point") {
1580
+ const anyPoint = candidates.find(
1581
+ (c) => isCandidateGeometryType(c, POINT_GEOMETRY_TYPES2)
1582
+ );
1583
+ if (anyPoint) {
1584
+ return getResult(anyPoint, "point:first-point-geometry");
1585
+ }
1586
+ }
1489
1587
  const sameLayer = candidates.filter(
1490
1588
  (candidate) => isLayerIdMatch(candidateLayerId(candidate), expectedLayerId)
1491
1589
  );
@@ -1922,7 +2020,7 @@ var ZenitMap = (0, import_react5.forwardRef)(({
1922
2020
  const ensureLayerPanes = (0, import_react5.useCallback)(
1923
2021
  (targetMap, targetLayers) => {
1924
2022
  const fillBaseZIndex = 400;
1925
- const pointsBaseZIndex = 700;
2023
+ const pointsBaseZIndex = 750;
1926
2024
  targetLayers.forEach((layer) => {
1927
2025
  const order = Number.isFinite(layer.displayOrder) ? layer.displayOrder : 0;
1928
2026
  const orderOffset = Math.max(0, Math.min(order, 150));
@@ -2006,7 +2104,10 @@ var ZenitMap = (0, import_react5.forwardRef)(({
2006
2104
  className: "zenit-map-tooltip"
2007
2105
  });
2008
2106
  }
2009
- layer.on("click", () => {
2107
+ layer.on("click", (e) => {
2108
+ if (clickIntent === "point") {
2109
+ import_leaflet4.default.DomEvent.stopPropagation(e);
2110
+ }
2010
2111
  if (featureInfoMode === "popup" && client && layerId !== void 0 && !extractDescriptionValue(feature?.properties) && feature?.geometry) {
2011
2112
  if (DEV_MODE2) {
2012
2113
  console.debug("[ZenitMap] click/intersect:start", {
@@ -2106,11 +2207,16 @@ var ZenitMap = (0, import_react5.forwardRef)(({
2106
2207
  properties: feature?.properties ?? void 0
2107
2208
  });
2108
2209
  }, [currentZoom, resolveLayerStyle]);
2109
- const makeStyleFnForLayer = (0, import_react5.useCallback)((layerId) => {
2110
- return (feature, layerType, baseOpacity) => {
2111
- return buildLayerStyle(layerId, baseOpacity ?? 1, feature, layerType);
2112
- };
2113
- }, [buildLayerStyle]);
2210
+ const styleFnByLayerId = (0, import_react5.useMemo)(() => {
2211
+ const next = /* @__PURE__ */ new Map();
2212
+ orderedLayers.forEach((layerState) => {
2213
+ const layerId = layerState.mapLayer.layerId;
2214
+ next.set(String(layerId), (feature, layerType, baseOpacity) => {
2215
+ return buildLayerStyle(layerId, baseOpacity ?? 1, feature, layerType);
2216
+ });
2217
+ });
2218
+ return next;
2219
+ }, [buildLayerStyle, orderedLayers]);
2114
2220
  (0, import_react5.useImperativeHandle)(ref, () => ({
2115
2221
  setLayerOpacity: (layerId, opacity) => {
2116
2222
  upsertUiOverride(layerId, { overrideOpacity: opacity });
@@ -2277,7 +2383,7 @@ var ZenitMap = (0, import_react5.forwardRef)(({
2277
2383
  fillPaneName,
2278
2384
  pointsPaneName,
2279
2385
  layerType,
2280
- styleFn: makeStyleFnForLayer(layerState.mapLayer.layerId),
2386
+ styleFn: styleFnByLayerId.get(String(layerState.mapLayer.layerId)) ?? ((feature, layerType2, baseOpacity2) => buildLayerStyle(layerState.mapLayer.layerId, baseOpacity2 ?? 1, feature, layerType2)),
2281
2387
  onEachFeature: overlayOnEachFeature,
2282
2388
  onPolygonLabel: labelKey ? (feature, layer) => {
2283
2389
  const geometryType = feature?.geometry?.type;
@@ -2421,7 +2527,7 @@ var ZenitMap = (0, import_react5.forwardRef)(({
2421
2527
  ZenitMap.displayName = "ZenitMap";
2422
2528
 
2423
2529
  // src/react/ZenitLayerManager.tsx
2424
- var import_react7 = __toESM(require("react"));
2530
+ var import_react8 = __toESM(require("react"));
2425
2531
 
2426
2532
  // src/react/icons.tsx
2427
2533
  var import_lucide_react = require("lucide-react");
@@ -2779,9 +2885,191 @@ var ZenitSelect = ({
2779
2885
  ] });
2780
2886
  };
2781
2887
 
2782
- // src/react/ZenitLayerManager.tsx
2888
+ // src/react/ui/ZenitCombobox.tsx
2889
+ var import_react7 = __toESM(require("react"));
2783
2890
  var import_jsx_runtime5 = require("react/jsx-runtime");
2891
+ var ZenitCombobox = ({
2892
+ options,
2893
+ value,
2894
+ onChange,
2895
+ placeholder = "Seleccionar\u2026",
2896
+ searchPlaceholder = "Buscar\u2026",
2897
+ disabled = false
2898
+ }) => {
2899
+ const rootRef = import_react7.default.useRef(null);
2900
+ const [isOpen, setIsOpen] = import_react7.default.useState(false);
2901
+ const [query, setQuery] = import_react7.default.useState("");
2902
+ const filteredOptions = import_react7.default.useMemo(() => {
2903
+ const normalized = query.trim().toLowerCase();
2904
+ if (!normalized) return options;
2905
+ return options.filter((option) => option.toLowerCase().includes(normalized));
2906
+ }, [options, query]);
2907
+ import_react7.default.useEffect(() => {
2908
+ if (!isOpen) return;
2909
+ const onClickOutside = (event) => {
2910
+ if (!rootRef.current?.contains(event.target)) {
2911
+ setIsOpen(false);
2912
+ }
2913
+ };
2914
+ const onEscape = (event) => {
2915
+ if (event.key === "Escape") {
2916
+ setIsOpen(false);
2917
+ }
2918
+ };
2919
+ document.addEventListener("mousedown", onClickOutside);
2920
+ document.addEventListener("keydown", onEscape);
2921
+ return () => {
2922
+ document.removeEventListener("mousedown", onClickOutside);
2923
+ document.removeEventListener("keydown", onEscape);
2924
+ };
2925
+ }, [isOpen]);
2926
+ import_react7.default.useEffect(() => {
2927
+ if (!isOpen) {
2928
+ setQuery("");
2929
+ }
2930
+ }, [isOpen]);
2931
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: rootRef, className: "zenit-combobox-root", style: { position: "relative" }, children: [
2932
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `
2933
+ .zenit-combobox-trigger {
2934
+ width: 100%;
2935
+ min-height: 40px;
2936
+ height: 40px;
2937
+ border: 1px solid #cbd5e1;
2938
+ border-radius: 6px;
2939
+ background: #ffffff;
2940
+ color: #0f172a;
2941
+ display: inline-flex;
2942
+ align-items: center;
2943
+ padding: 0 12px;
2944
+ font-size: 14px;
2945
+ line-height: 1.25;
2946
+ cursor: pointer;
2947
+ text-align: left;
2948
+ }
2949
+ .zenit-combobox-trigger.is-placeholder {
2950
+ color: #64748b;
2951
+ }
2952
+ .zenit-combobox-trigger:disabled {
2953
+ opacity: 0.6;
2954
+ cursor: not-allowed;
2955
+ }
2956
+ .zenit-combobox-content {
2957
+ position: absolute;
2958
+ top: calc(100% + 6px);
2959
+ left: 0;
2960
+ right: 0;
2961
+ border: 1px solid #cbd5e1;
2962
+ border-radius: 6px;
2963
+ background: #ffffff;
2964
+ box-shadow: 0 10px 25px rgba(15, 23, 42, 0.18);
2965
+ padding: 8px;
2966
+ z-index: 4000;
2967
+ }
2968
+ .zenit-combobox-search {
2969
+ width: 100%;
2970
+ min-height: 36px;
2971
+ border: 1px solid #cbd5e1;
2972
+ border-radius: 6px;
2973
+ background: #ffffff;
2974
+ color: #0f172a;
2975
+ padding: 0 10px;
2976
+ font-size: 14px;
2977
+ margin-bottom: 8px;
2978
+ box-sizing: border-box;
2979
+ }
2980
+ .zenit-combobox-list {
2981
+ max-height: 220px;
2982
+ overflow-y: auto;
2983
+ }
2984
+ .zenit-combobox-item {
2985
+ width: 100%;
2986
+ border-radius: 4px;
2987
+ color: #0f172a;
2988
+ font-size: 14px;
2989
+ min-height: 34px;
2990
+ padding: 8px 10px;
2991
+ cursor: pointer;
2992
+ user-select: none;
2993
+ }
2994
+ .zenit-combobox-item:hover { background: #f1f5f9; }
2995
+ .zenit-combobox-item.is-selected { background: #e2e8f0; font-weight: 600; }
2996
+ ` }),
2997
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2998
+ "button",
2999
+ {
3000
+ type: "button",
3001
+ className: `zenit-combobox-trigger${!value ? " is-placeholder" : ""}`,
3002
+ disabled,
3003
+ onClick: () => !disabled && setIsOpen((prev) => !prev),
3004
+ children: value || placeholder
3005
+ }
3006
+ ),
3007
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "zenit-combobox-content", children: [
3008
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3009
+ "input",
3010
+ {
3011
+ className: "zenit-combobox-search",
3012
+ value: query,
3013
+ onChange: (event) => setQuery(event.target.value),
3014
+ placeholder: searchPlaceholder,
3015
+ autoFocus: true
3016
+ }
3017
+ ),
3018
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "zenit-combobox-list", children: [
3019
+ filteredOptions.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "zenit-combobox-item", style: { color: "#64748b", cursor: "default" }, children: "Sin coincidencias" }),
3020
+ filteredOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3021
+ "div",
3022
+ {
3023
+ className: `zenit-combobox-item${option === value ? " is-selected" : ""}`,
3024
+ onClick: () => {
3025
+ onChange(option);
3026
+ setIsOpen(false);
3027
+ },
3028
+ children: option
3029
+ },
3030
+ option
3031
+ ))
3032
+ ] })
3033
+ ] })
3034
+ ] });
3035
+ };
3036
+
3037
+ // src/react/ZenitLayerManager.tsx
3038
+ var import_jsx_runtime6 = require("react/jsx-runtime");
2784
3039
  var FLOAT_TOLERANCE = 1e-3;
3040
+ var CATALOG_FIELD_BLACKLIST = /* @__PURE__ */ new Set([
3041
+ "mapids",
3042
+ "mapId",
3043
+ "mapIDs",
3044
+ "mapId",
3045
+ "field",
3046
+ "Field",
3047
+ "objectid",
3048
+ "OBJECTID",
3049
+ "objectId",
3050
+ "gforms",
3051
+ "GFORMS",
3052
+ "nomina",
3053
+ "NOMINA",
3054
+ "shape_area",
3055
+ "SHAPE_AREA",
3056
+ "shape_leng",
3057
+ "SHAPE_LENG",
3058
+ "fid",
3059
+ "FID",
3060
+ "gid",
3061
+ "GID",
3062
+ "created_at",
3063
+ "updated_at",
3064
+ "created_user",
3065
+ "last_edited_user",
3066
+ "globalid",
3067
+ "GLOBALID"
3068
+ ]);
3069
+ function isFieldVisible(key) {
3070
+ return !CATALOG_FIELD_BLACKLIST.has(key) && !key.startsWith("_") && !key.startsWith("__");
3071
+ }
3072
+ var matchesWhitelist = (key, whitelist) => whitelist.some((w) => w.toUpperCase() === key.toUpperCase());
2785
3073
  function areEffectiveStatesEqual(a, b) {
2786
3074
  if (a.length !== b.length) return false;
2787
3075
  return a.every((state, index) => {
@@ -2820,26 +3108,29 @@ var ZenitLayerManager = ({
2820
3108
  layerFeatureCounts,
2821
3109
  mapLayers,
2822
3110
  onApplyLayerFilter,
2823
- onClearLayerFilter
3111
+ onClearLayerFilter,
3112
+ availableFilterLayers = [],
3113
+ filterFieldWhitelist = []
2824
3114
  }) => {
2825
- const [map, setMap] = (0, import_react7.useState)(null);
2826
- const [loadingMap, setLoadingMap] = (0, import_react7.useState)(false);
2827
- const [mapError, setMapError] = (0, import_react7.useState)(null);
2828
- const [layers, setLayers] = (0, import_react7.useState)([]);
2829
- const [activeTab, setActiveTab] = (0, import_react7.useState)("layers");
2830
- const [panelVisible, setPanelVisible] = (0, import_react7.useState)(true);
2831
- const [selectedFilterLayerId, setSelectedFilterLayerId] = (0, import_react7.useState)("");
2832
- const [selectedFilterField, setSelectedFilterField] = (0, import_react7.useState)("");
2833
- const [selectedFilterValue, setSelectedFilterValue] = (0, import_react7.useState)("");
2834
- const [catalogByLayerField, setCatalogByLayerField] = (0, import_react7.useState)({});
2835
- const [loadingCatalog, setLoadingCatalog] = (0, import_react7.useState)(false);
2836
- const [applyingFilter, setApplyingFilter] = (0, import_react7.useState)(false);
2837
- const [filterError, setFilterError] = (0, import_react7.useState)(null);
2838
- const [appliedFilter, setAppliedFilter] = (0, import_react7.useState)(null);
2839
- const catalogAbortRef = (0, import_react7.useRef)(null);
2840
- const lastEmittedStatesRef = (0, import_react7.useRef)(null);
3115
+ const [map, setMap] = (0, import_react8.useState)(null);
3116
+ const [loadingMap, setLoadingMap] = (0, import_react8.useState)(false);
3117
+ const [mapError, setMapError] = (0, import_react8.useState)(null);
3118
+ const [layers, setLayers] = (0, import_react8.useState)([]);
3119
+ const [activeTab, setActiveTab] = (0, import_react8.useState)("layers");
3120
+ const [panelVisible, setPanelVisible] = (0, import_react8.useState)(true);
3121
+ const [selectedFilterLayerId, setSelectedFilterLayerId] = (0, import_react8.useState)("");
3122
+ const [selectedFilterField, setSelectedFilterField] = (0, import_react8.useState)("");
3123
+ const [selectedFilterValue, setSelectedFilterValue] = (0, import_react8.useState)("");
3124
+ const [catalogByLayerField, setCatalogByLayerField] = (0, import_react8.useState)({});
3125
+ const [catalogFieldsByLayer, setCatalogFieldsByLayer] = (0, import_react8.useState)({});
3126
+ const [loadingCatalog, setLoadingCatalog] = (0, import_react8.useState)(false);
3127
+ const [applyingFilter, setApplyingFilter] = (0, import_react8.useState)(false);
3128
+ const [filterError, setFilterError] = (0, import_react8.useState)(null);
3129
+ const [appliedFilter, setAppliedFilter] = (0, import_react8.useState)(null);
3130
+ const catalogAbortRef = (0, import_react8.useRef)(null);
3131
+ const lastEmittedStatesRef = (0, import_react8.useRef)(null);
2841
3132
  const isControlled = Array.isArray(layerStates) && typeof onLayerStatesChange === "function";
2842
- const baseStates = (0, import_react7.useMemo)(
3133
+ const baseStates = (0, import_react8.useMemo)(
2843
3134
  () => initLayerStates(
2844
3135
  layers.map((entry) => ({
2845
3136
  ...entry.mapLayer,
@@ -2850,7 +3141,7 @@ var ZenitLayerManager = ({
2850
3141
  ),
2851
3142
  [layers]
2852
3143
  );
2853
- const overrideStates = (0, import_react7.useMemo)(
3144
+ const overrideStates = (0, import_react8.useMemo)(
2854
3145
  () => layers.map(
2855
3146
  (entry) => ({
2856
3147
  layerId: entry.mapLayer.layerId,
@@ -2860,11 +3151,11 @@ var ZenitLayerManager = ({
2860
3151
  ),
2861
3152
  [layers]
2862
3153
  );
2863
- const effectiveStates = (0, import_react7.useMemo)(
3154
+ const effectiveStates = (0, import_react8.useMemo)(
2864
3155
  () => layerStates ?? applyLayerOverrides(baseStates, overrideStates),
2865
3156
  [baseStates, layerStates, overrideStates]
2866
3157
  );
2867
- const layerMetaIndex = (0, import_react7.useMemo)(() => {
3158
+ const layerMetaIndex = (0, import_react8.useMemo)(() => {
2868
3159
  const index = /* @__PURE__ */ new Map();
2869
3160
  mapLayers?.forEach((entry) => {
2870
3161
  const key = String(entry.layerId);
@@ -2878,7 +3169,7 @@ var ZenitLayerManager = ({
2878
3169
  });
2879
3170
  return index;
2880
3171
  }, [map, mapLayers]);
2881
- const resolveUserOpacity = import_react7.default.useCallback((state) => {
3172
+ const resolveUserOpacity = import_react8.default.useCallback((state) => {
2882
3173
  if (typeof state.overrideOpacity === "number") return state.overrideOpacity;
2883
3174
  if (typeof state.overrideOpacity === "string") {
2884
3175
  const parsed = Number.parseFloat(state.overrideOpacity);
@@ -2886,7 +3177,7 @@ var ZenitLayerManager = ({
2886
3177
  }
2887
3178
  return state.opacity ?? 1;
2888
3179
  }, []);
2889
- const resolveEffectiveOpacity = import_react7.default.useCallback(
3180
+ const resolveEffectiveOpacity = import_react8.default.useCallback(
2890
3181
  (layerId, userOpacity) => {
2891
3182
  if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
2892
3183
  return userOpacity;
@@ -2902,7 +3193,7 @@ var ZenitLayerManager = ({
2902
3193
  },
2903
3194
  [autoOpacityConfig, autoOpacityOnZoom, layerMetaIndex, mapZoom]
2904
3195
  );
2905
- const effectiveStatesWithZoom = (0, import_react7.useMemo)(() => {
3196
+ const effectiveStatesWithZoom = (0, import_react8.useMemo)(() => {
2906
3197
  if (!autoOpacityOnZoom || typeof mapZoom !== "number") {
2907
3198
  return effectiveStates;
2908
3199
  }
@@ -2916,7 +3207,7 @@ var ZenitLayerManager = ({
2916
3207
  };
2917
3208
  });
2918
3209
  }, [autoOpacityOnZoom, effectiveStates, mapZoom, resolveEffectiveOpacity, resolveUserOpacity]);
2919
- (0, import_react7.useEffect)(() => {
3210
+ (0, import_react8.useEffect)(() => {
2920
3211
  let cancelled = false;
2921
3212
  setLoadingMap(true);
2922
3213
  setMapError(null);
@@ -2948,12 +3239,12 @@ var ZenitLayerManager = ({
2948
3239
  cancelled = true;
2949
3240
  };
2950
3241
  }, [client.maps, mapId]);
2951
- (0, import_react7.useEffect)(() => {
3242
+ (0, import_react8.useEffect)(() => {
2952
3243
  if (!showUploadTab && activeTab === "upload") {
2953
3244
  setActiveTab("layers");
2954
3245
  }
2955
3246
  }, [activeTab, showUploadTab]);
2956
- (0, import_react7.useEffect)(() => {
3247
+ (0, import_react8.useEffect)(() => {
2957
3248
  if (isControlled) return;
2958
3249
  if (!onLayerStatesChange) return;
2959
3250
  const emitStates = autoOpacityOnZoom && typeof mapZoom === "number" ? effectiveStatesWithZoom : effectiveStates;
@@ -2971,7 +3262,7 @@ var ZenitLayerManager = ({
2971
3262
  mapZoom,
2972
3263
  onLayerStatesChange
2973
3264
  ]);
2974
- const updateLayerVisible = import_react7.default.useCallback(
3265
+ const updateLayerVisible = import_react8.default.useCallback(
2975
3266
  (layerId, visible) => {
2976
3267
  if (!onLayerStatesChange) return;
2977
3268
  const next = effectiveStates.map(
@@ -2981,7 +3272,7 @@ var ZenitLayerManager = ({
2981
3272
  },
2982
3273
  [effectiveStates, onLayerStatesChange]
2983
3274
  );
2984
- const updateLayerOpacity = import_react7.default.useCallback(
3275
+ const updateLayerOpacity = import_react8.default.useCallback(
2985
3276
  (layerId, opacity) => {
2986
3277
  if (!onLayerStatesChange) return;
2987
3278
  const adjustedOpacity = resolveEffectiveOpacity(layerId, opacity);
@@ -2992,7 +3283,7 @@ var ZenitLayerManager = ({
2992
3283
  },
2993
3284
  [effectiveStates, onLayerStatesChange, resolveEffectiveOpacity]
2994
3285
  );
2995
- const resolveFeatureCount = import_react7.default.useCallback(
3286
+ const resolveFeatureCount = import_react8.default.useCallback(
2996
3287
  (layerId, layer) => {
2997
3288
  const resolvedFeatureCount = layerFeatureCounts?.[layerId] ?? layerFeatureCounts?.[String(layerId)];
2998
3289
  if (typeof resolvedFeatureCount === "number") return resolvedFeatureCount;
@@ -3001,7 +3292,7 @@ var ZenitLayerManager = ({
3001
3292
  },
3002
3293
  [layerFeatureCounts]
3003
3294
  );
3004
- const decoratedLayers = (0, import_react7.useMemo)(() => {
3295
+ const decoratedLayers = (0, import_react8.useMemo)(() => {
3005
3296
  return layers.map((entry) => ({
3006
3297
  ...entry,
3007
3298
  effective: effectiveStates.find((state) => state.layerId === entry.mapLayer.layerId),
@@ -3030,7 +3321,7 @@ var ZenitLayerManager = ({
3030
3321
  return String(a.mapLayer.layerId).localeCompare(String(b.mapLayer.layerId));
3031
3322
  });
3032
3323
  }, [effectiveStates, layers, resolveFeatureCount]);
3033
- const hasPrefilters = (0, import_react7.useMemo)(() => {
3324
+ const hasPrefilters = (0, import_react8.useMemo)(() => {
3034
3325
  const candidates = [...mapLayers ?? [], ...map?.mapLayers ?? []];
3035
3326
  return candidates.some((layer) => {
3036
3327
  const record = layer;
@@ -3038,23 +3329,32 @@ var ZenitLayerManager = ({
3038
3329
  return !!applied && typeof applied === "object" && Object.keys(applied).length > 0;
3039
3330
  });
3040
3331
  }, [map?.mapLayers, mapLayers]);
3041
- const filterableLayers = (0, import_react7.useMemo)(() => {
3332
+ const filterableLayers = (0, import_react8.useMemo)(() => {
3333
+ const forcedLayerIds = new Set(availableFilterLayers.map((layerId) => String(layerId)));
3042
3334
  return decoratedLayers.filter((entry) => {
3043
3335
  const prefilters = entry.mapLayer.layerConfig?.prefilters;
3044
- return !!prefilters && Object.keys(prefilters).length > 0;
3336
+ if (prefilters && Object.keys(prefilters).length > 0) return true;
3337
+ if (forcedLayerIds.has(String(entry.mapLayer.layerId))) return true;
3338
+ const layerType = (entry.mapLayer.layerType ?? entry.layer?.layerType ?? "").toString().toLowerCase();
3339
+ return layerType === "multipolygon";
3045
3340
  });
3046
- }, [decoratedLayers]);
3047
- const selectedFilterLayer = (0, import_react7.useMemo)(
3341
+ }, [availableFilterLayers, decoratedLayers]);
3342
+ const selectedFilterLayer = (0, import_react8.useMemo)(
3048
3343
  () => filterableLayers.find((layer) => String(layer.mapLayer.layerId) === selectedFilterLayerId) ?? null,
3049
3344
  [filterableLayers, selectedFilterLayerId]
3050
3345
  );
3051
- const filterFields = (0, import_react7.useMemo)(() => {
3052
- const prefilters = selectedFilterLayer?.mapLayer.layerConfig?.prefilters;
3053
- return prefilters ? Object.keys(prefilters) : [];
3054
- }, [selectedFilterLayer]);
3346
+ const filterFields = (0, import_react8.useMemo)(() => {
3347
+ if (!selectedFilterLayer) return [];
3348
+ const prefilters = selectedFilterLayer.mapLayer.layerConfig?.prefilters;
3349
+ if (prefilters) {
3350
+ const keys = Object.keys(prefilters);
3351
+ if (keys.length > 0) return keys;
3352
+ }
3353
+ return catalogFieldsByLayer[String(selectedFilterLayer.mapLayer.layerId)] ?? [];
3354
+ }, [catalogFieldsByLayer, selectedFilterLayer]);
3055
3355
  const activeCatalogKey = selectedFilterLayer ? `${selectedFilterLayer.mapLayer.layerId}:${selectedFilterField}` : null;
3056
3356
  const activeCatalogValues = activeCatalogKey ? catalogByLayerField[activeCatalogKey] ?? [] : [];
3057
- const extractCatalogValues = import_react7.default.useCallback((catalogData, field) => {
3357
+ const extractCatalogValues = import_react8.default.useCallback((catalogData, field) => {
3058
3358
  const values = /* @__PURE__ */ new Set();
3059
3359
  const pushValue = (value) => {
3060
3360
  if (value === null || value === void 0) return;
@@ -3091,7 +3391,46 @@ var ZenitLayerManager = ({
3091
3391
  }
3092
3392
  return [...values].sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
3093
3393
  }, []);
3094
- (0, import_react7.useEffect)(() => {
3394
+ const extractCatalogFieldMap = import_react8.default.useCallback((catalogData, whitelist) => {
3395
+ if (!catalogData || typeof catalogData !== "object") return {};
3396
+ const maybeRecord = catalogData;
3397
+ const fieldNames = /* @__PURE__ */ new Set();
3398
+ Object.entries(maybeRecord).forEach(([key, value]) => {
3399
+ if (Array.isArray(value) && key !== "items" && key !== "features") {
3400
+ if (isFieldVisible(key)) fieldNames.add(key);
3401
+ }
3402
+ });
3403
+ const items = maybeRecord.items;
3404
+ if (Array.isArray(items)) {
3405
+ items.forEach((item) => {
3406
+ if (!item || typeof item !== "object") return;
3407
+ const row = item;
3408
+ if (row.field !== null && row.field !== void 0) {
3409
+ const fieldName = String(row.field).trim();
3410
+ if (fieldName && isFieldVisible(fieldName)) fieldNames.add(fieldName);
3411
+ }
3412
+ });
3413
+ }
3414
+ const features = maybeRecord.features;
3415
+ if (Array.isArray(features)) {
3416
+ features.forEach((feature) => {
3417
+ if (!feature || typeof feature !== "object") return;
3418
+ const properties = feature.properties;
3419
+ if (!properties || typeof properties !== "object") return;
3420
+ Object.keys(properties).forEach((key) => {
3421
+ if (isFieldVisible(key)) fieldNames.add(key);
3422
+ });
3423
+ });
3424
+ }
3425
+ const normalizedWhitelist = (whitelist ?? []).map((item) => String(item).trim()).filter(Boolean);
3426
+ const resolvedFieldNames = normalizedWhitelist.length > 0 ? [...fieldNames].filter((field) => matchesWhitelist(field, normalizedWhitelist)) : [...fieldNames];
3427
+ const next = {};
3428
+ resolvedFieldNames.forEach((field) => {
3429
+ next[field] = extractCatalogValues(catalogData, field);
3430
+ });
3431
+ return next;
3432
+ }, [extractCatalogValues]);
3433
+ (0, import_react8.useEffect)(() => {
3095
3434
  if (!filterableLayers.length) {
3096
3435
  setSelectedFilterLayerId("");
3097
3436
  return;
@@ -3100,7 +3439,7 @@ var ZenitLayerManager = ({
3100
3439
  setSelectedFilterLayerId(String(filterableLayers[0].mapLayer.layerId));
3101
3440
  }
3102
3441
  }, [filterableLayers, selectedFilterLayerId]);
3103
- (0, import_react7.useEffect)(() => {
3442
+ (0, import_react8.useEffect)(() => {
3104
3443
  if (!filterFields.length) {
3105
3444
  setSelectedFilterField("");
3106
3445
  return;
@@ -3110,24 +3449,42 @@ var ZenitLayerManager = ({
3110
3449
  setSelectedFilterValue("");
3111
3450
  }
3112
3451
  }, [filterFields, selectedFilterField]);
3113
- (0, import_react7.useEffect)(() => {
3452
+ (0, import_react8.useEffect)(() => {
3114
3453
  if (hasPrefilters && activeTab === "filters") {
3115
3454
  setActiveTab("layers");
3116
3455
  }
3117
3456
  }, [activeTab, hasPrefilters]);
3118
- (0, import_react7.useEffect)(() => {
3457
+ (0, import_react8.useEffect)(() => {
3119
3458
  if (activeTab !== "filters") return;
3120
- if (!selectedFilterLayer || !selectedFilterField || !activeCatalogKey) return;
3121
- if (catalogByLayerField[activeCatalogKey]) return;
3459
+ if (!selectedFilterLayer) return;
3460
+ const layerId = selectedFilterLayer.mapLayer.layerId;
3461
+ const layerKey = String(layerId);
3462
+ const prefilters = selectedFilterLayer.mapLayer.layerConfig?.prefilters;
3463
+ const requiresCatalogForFields = !prefilters || Object.keys(prefilters).length === 0;
3464
+ const hasFieldsLoaded = (catalogFieldsByLayer[layerKey]?.length ?? 0) > 0;
3465
+ const needsLayerCatalog = requiresCatalogForFields && !hasFieldsLoaded;
3466
+ const needsFieldCatalog = Boolean(activeCatalogKey && selectedFilterField && !catalogByLayerField[activeCatalogKey]);
3467
+ if (!needsLayerCatalog && !needsFieldCatalog) return;
3122
3468
  catalogAbortRef.current?.abort();
3123
3469
  const controller = new AbortController();
3124
3470
  catalogAbortRef.current = controller;
3125
3471
  setLoadingCatalog(true);
3126
3472
  setFilterError(null);
3127
- client.layers.getLayerFeaturesCatalog(selectedFilterLayer.mapLayer.layerId).then((response) => {
3473
+ client.layers.getLayerFeaturesCatalog(layerId).then((response) => {
3128
3474
  if (controller.signal.aborted) return;
3129
- const values = extractCatalogValues(response.data, selectedFilterField);
3130
- setCatalogByLayerField((prev) => ({ ...prev, [activeCatalogKey]: values }));
3475
+ const fieldMap = extractCatalogFieldMap(response.data, filterFieldWhitelist);
3476
+ const fields = Object.keys(fieldMap);
3477
+ setCatalogFieldsByLayer((prev) => ({ ...prev, [layerKey]: fields }));
3478
+ setCatalogByLayerField((prev) => {
3479
+ const next = { ...prev };
3480
+ fields.forEach((field) => {
3481
+ const key = `${layerKey}:${field}`;
3482
+ if (!next[key]) {
3483
+ next[key] = fieldMap[field] ?? [];
3484
+ }
3485
+ });
3486
+ return next;
3487
+ });
3131
3488
  }).catch((error) => {
3132
3489
  if (controller.signal.aborted) return;
3133
3490
  const message = error instanceof Error ? error.message : "No se pudo cargar el cat\xE1logo";
@@ -3138,8 +3495,8 @@ var ZenitLayerManager = ({
3138
3495
  return () => {
3139
3496
  controller.abort();
3140
3497
  };
3141
- }, [activeCatalogKey, activeTab, catalogByLayerField, client.layers, extractCatalogValues, selectedFilterField, selectedFilterLayer]);
3142
- const handleApplyFilter = import_react7.default.useCallback(async () => {
3498
+ }, [activeCatalogKey, activeTab, catalogByLayerField, catalogFieldsByLayer, client.layers, extractCatalogFieldMap, filterFieldWhitelist, selectedFilterField, selectedFilterLayer]);
3499
+ const handleApplyFilter = import_react8.default.useCallback(async () => {
3143
3500
  if (!selectedFilterLayer || !selectedFilterField || !selectedFilterValue || !onApplyLayerFilter) return;
3144
3501
  setApplyingFilter(true);
3145
3502
  setFilterError(null);
@@ -3161,7 +3518,7 @@ var ZenitLayerManager = ({
3161
3518
  setApplyingFilter(false);
3162
3519
  }
3163
3520
  }, [onApplyLayerFilter, selectedFilterField, selectedFilterLayer, selectedFilterValue]);
3164
- const handleClearFilter = import_react7.default.useCallback(async () => {
3521
+ const handleClearFilter = import_react8.default.useCallback(async () => {
3165
3522
  if (!selectedFilterLayer) return;
3166
3523
  setApplyingFilter(true);
3167
3524
  setFilterError(null);
@@ -3176,7 +3533,7 @@ var ZenitLayerManager = ({
3176
3533
  setApplyingFilter(false);
3177
3534
  }
3178
3535
  }, [onClearLayerFilter, selectedFilterField, selectedFilterLayer]);
3179
- const resolveLayerStyle = import_react7.default.useCallback(
3536
+ const resolveLayerStyle = import_react8.default.useCallback(
3180
3537
  (layerId) => {
3181
3538
  const layerKey = String(layerId);
3182
3539
  const fromProp = mapLayers?.find((entry) => String(entry.layerId) === layerKey)?.style;
@@ -3190,6 +3547,22 @@ var ZenitLayerManager = ({
3190
3547
  },
3191
3548
  [map, mapLayers]
3192
3549
  );
3550
+ const allVisible = decoratedLayers.every(
3551
+ (entry) => entry.effective?.visible ?? false
3552
+ );
3553
+ const anyVisible = decoratedLayers.some(
3554
+ (entry) => entry.effective?.visible ?? false
3555
+ );
3556
+ const handleToggleAllLayers = import_react8.default.useCallback(() => {
3557
+ if (!onLayerStatesChange) return;
3558
+ const nextVisible = !anyVisible;
3559
+ const next = effectiveStates.map((state) => ({
3560
+ ...state,
3561
+ visible: nextVisible,
3562
+ overrideVisible: nextVisible
3563
+ }));
3564
+ onLayerStatesChange(next);
3565
+ }, [anyVisible, effectiveStates, onLayerStatesChange]);
3193
3566
  const panelStyle = {
3194
3567
  width: 360,
3195
3568
  borderLeft: side === "right" ? "1px solid #e2e8f0" : void 0,
@@ -3206,10 +3579,10 @@ var ZenitLayerManager = ({
3206
3579
  ...height ? { height } : {}
3207
3580
  };
3208
3581
  if (loadingMap) {
3209
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className, style: panelStyle, children: "Cargando capas\u2026" });
3582
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className, style: panelStyle, children: "Cargando capas\u2026" });
3210
3583
  }
3211
3584
  if (mapError) {
3212
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className, style: { ...panelStyle, color: "#c53030" }, children: [
3585
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className, style: { ...panelStyle, color: "#c53030" }, children: [
3213
3586
  "Error al cargar mapa: ",
3214
3587
  mapError
3215
3588
  ] });
@@ -3227,7 +3600,7 @@ var ZenitLayerManager = ({
3227
3600
  boxShadow: "0 1px 0 rgba(148, 163, 184, 0.25)"
3228
3601
  };
3229
3602
  const renderLayerCards = () => {
3230
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: decoratedLayers.map((layerState) => {
3603
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: decoratedLayers.map((layerState) => {
3231
3604
  const layerId = layerState.mapLayer.layerId;
3232
3605
  const layerName = layerState.layerName ?? `Capa ${layerId}`;
3233
3606
  const visible = layerState.effective?.visible ?? false;
@@ -3237,7 +3610,7 @@ var ZenitLayerManager = ({
3237
3610
  const muted = !visible;
3238
3611
  const opacityPercent = Math.round(userOpacity * 100);
3239
3612
  const sliderBackground = `linear-gradient(to right, ${layerColor} 0%, ${layerColor} ${opacityPercent}%, #e5e7eb ${opacityPercent}%, #e5e7eb 100%)`;
3240
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3613
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3241
3614
  "div",
3242
3615
  {
3243
3616
  className: `zlm-card${muted ? " is-muted" : ""}`,
@@ -3252,9 +3625,9 @@ var ZenitLayerManager = ({
3252
3625
  width: "100%"
3253
3626
  },
3254
3627
  children: [
3255
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
3256
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", gap: 10, alignItems: "flex-start", minWidth: 0, flex: 1 }, children: [
3257
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3628
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
3629
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", gap: 10, alignItems: "flex-start", minWidth: 0, flex: 1 }, children: [
3630
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3258
3631
  "div",
3259
3632
  {
3260
3633
  style: {
@@ -3269,7 +3642,7 @@ var ZenitLayerManager = ({
3269
3642
  title: "Color de la capa"
3270
3643
  }
3271
3644
  ),
3272
- showLayerVisibilityIcon && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3645
+ showLayerVisibilityIcon && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3273
3646
  "button",
3274
3647
  {
3275
3648
  type: "button",
@@ -3280,11 +3653,11 @@ var ZenitLayerManager = ({
3280
3653
  )
3281
3654
  ),
3282
3655
  "aria-label": visible ? "Ocultar capa" : "Mostrar capa",
3283
- children: visible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Eye, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.EyeOff, { size: 16 })
3656
+ children: visible ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Eye, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.EyeOff, { size: 16 })
3284
3657
  }
3285
3658
  ),
3286
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { minWidth: 0, flex: 1 }, children: [
3287
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3659
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { minWidth: 0, flex: 1 }, children: [
3660
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3288
3661
  "div",
3289
3662
  {
3290
3663
  className: "zlm-layer-name",
@@ -3302,26 +3675,26 @@ var ZenitLayerManager = ({
3302
3675
  children: layerName
3303
3676
  }
3304
3677
  ),
3305
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { color: muted ? "#94a3b8" : "#64748b", fontSize: 12 }, children: [
3678
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { color: muted ? "#94a3b8" : "#64748b", fontSize: 12 }, children: [
3306
3679
  "ID ",
3307
3680
  layerId
3308
3681
  ] })
3309
3682
  ] })
3310
3683
  ] }),
3311
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { display: "flex", alignItems: "flex-start", gap: 6, flexShrink: 0 }, children: typeof featureCount === "number" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "zlm-badge", children: [
3684
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", alignItems: "flex-start", gap: 6, flexShrink: 0 }, children: typeof featureCount === "number" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "zlm-badge", children: [
3312
3685
  featureCount.toLocaleString(),
3313
3686
  " features"
3314
3687
  ] }) })
3315
3688
  ] }),
3316
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { display: "flex", gap: 10, alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { flex: 1 }, children: [
3317
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 6, color: "#64748b", fontSize: 12 }, children: [
3318
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Opacidad" }),
3319
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
3689
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", gap: 10, alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { flex: 1 }, children: [
3690
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 6, color: "#64748b", fontSize: 12 }, children: [
3691
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "Opacidad" }),
3692
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
3320
3693
  opacityPercent,
3321
3694
  "%"
3322
3695
  ] })
3323
3696
  ] }),
3324
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3697
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3325
3698
  "input",
3326
3699
  {
3327
3700
  className: "zlm-range",
@@ -3359,8 +3732,8 @@ var ZenitLayerManager = ({
3359
3732
  );
3360
3733
  }) });
3361
3734
  };
3362
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: ["zenit-layer-manager", className].filter(Boolean).join(" "), style: panelStyle, children: [
3363
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `
3735
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: ["zenit-layer-manager", className].filter(Boolean).join(" "), style: panelStyle, children: [
3736
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `
3364
3737
  .zenit-layer-manager .zlm-card {
3365
3738
  transition: box-shadow 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
3366
3739
  box-shadow: 0 6px 16px rgba(15, 23, 42, 0.08);
@@ -3455,16 +3828,16 @@ var ZenitLayerManager = ({
3455
3828
  outline-offset: 2px;
3456
3829
  }
3457
3830
  ` }),
3458
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: headerStyle, children: [
3459
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
3460
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
3461
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontWeight: 800, fontSize: 16, color: "#0f172a" }, children: "Gesti\xF3n de Capas" }),
3462
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { color: "#64748b", fontSize: 12 }, children: [
3831
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: headerStyle, children: [
3832
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
3833
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
3834
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { fontWeight: 800, fontSize: 16, color: "#0f172a" }, children: "Gesti\xF3n de Capas" }),
3835
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { color: "#64748b", fontSize: 12 }, children: [
3463
3836
  "Mapa #",
3464
3837
  map.id
3465
3838
  ] })
3466
3839
  ] }),
3467
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3840
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3468
3841
  "button",
3469
3842
  {
3470
3843
  type: "button",
@@ -3472,13 +3845,13 @@ var ZenitLayerManager = ({
3472
3845
  className: "zlm-panel-toggle",
3473
3846
  "aria-label": panelVisible ? "Ocultar panel de capas" : "Mostrar panel de capas",
3474
3847
  children: [
3475
- panelVisible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Eye, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.EyeOff, { size: 16 }),
3848
+ panelVisible ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Eye, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.EyeOff, { size: 16 }),
3476
3849
  panelVisible ? "Ocultar" : "Mostrar"
3477
3850
  ]
3478
3851
  }
3479
3852
  )
3480
3853
  ] }),
3481
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3854
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3482
3855
  "div",
3483
3856
  {
3484
3857
  style: {
@@ -3491,38 +3864,38 @@ var ZenitLayerManager = ({
3491
3864
  background: "#f1f5f9"
3492
3865
  },
3493
3866
  children: [
3494
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3867
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3495
3868
  "button",
3496
3869
  {
3497
3870
  type: "button",
3498
3871
  className: `zlm-tab${activeTab === "layers" ? " is-active" : ""}`,
3499
3872
  onClick: () => setActiveTab("layers"),
3500
3873
  children: [
3501
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Layers, { size: 16 }),
3874
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Layers, { size: 16 }),
3502
3875
  "Capas"
3503
3876
  ]
3504
3877
  }
3505
3878
  ),
3506
- showUploadTab && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3879
+ showUploadTab && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3507
3880
  "button",
3508
3881
  {
3509
3882
  type: "button",
3510
3883
  className: `zlm-tab${activeTab === "upload" ? " is-active" : ""}`,
3511
3884
  onClick: () => setActiveTab("upload"),
3512
3885
  children: [
3513
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Upload, { size: 16 }),
3886
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Upload, { size: 16 }),
3514
3887
  "Subir"
3515
3888
  ]
3516
3889
  }
3517
3890
  ),
3518
- !hasPrefilters && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3891
+ !hasPrefilters && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3519
3892
  "button",
3520
3893
  {
3521
3894
  type: "button",
3522
3895
  className: `zlm-tab${activeTab === "filters" ? " is-active" : ""}`,
3523
3896
  onClick: () => setActiveTab("filters"),
3524
3897
  children: [
3525
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Layers, { size: 16 }),
3898
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Layers, { size: 16 }),
3526
3899
  "Filtros"
3527
3900
  ]
3528
3901
  }
@@ -3531,13 +3904,29 @@ var ZenitLayerManager = ({
3531
3904
  }
3532
3905
  )
3533
3906
  ] }),
3534
- panelVisible && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
3535
- hasPrefilters && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "zlm-badge", style: { marginBottom: 10 }, children: "Este mapa ya incluye filtros preaplicados" }),
3536
- activeTab === "layers" && renderLayerCards(),
3537
- !hasPrefilters && activeTab === "filters" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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__ */ (0, import_jsx_runtime5.jsx)("div", { style: { color: "#64748b", fontSize: 13 }, children: "No hay filtros disponibles para las capas de este mapa." }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
3538
- filterableLayers.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
3907
+ panelVisible && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { padding: "12px 10px 18px", overflowY: "auto", flex: 1, minHeight: 0 }, children: [
3908
+ hasPrefilters && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "zlm-badge", style: { marginBottom: 10 }, children: "Este mapa ya incluye filtros preaplicados" }),
3909
+ activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3910
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { marginBottom: 10 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3911
+ "button",
3912
+ {
3913
+ type: "button",
3914
+ className: "zlm-panel-toggle",
3915
+ onClick: handleToggleAllLayers,
3916
+ disabled: decoratedLayers.length === 0,
3917
+ "aria-label": anyVisible ? "Ocultar todas las capas" : "Mostrar todas las capas",
3918
+ children: [
3919
+ anyVisible ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.EyeOff, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Eye, { size: 14 }),
3920
+ anyVisible ? "Ocultar todas" : "Mostrar todas"
3921
+ ]
3922
+ }
3923
+ ) }),
3924
+ renderLayerCards()
3925
+ ] }),
3926
+ !hasPrefilters && activeTab === "filters" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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__ */ (0, import_jsx_runtime6.jsx)("div", { style: { color: "#64748b", fontSize: 13 }, children: "No hay filtros disponibles para las capas de este mapa." }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3927
+ filterableLayers.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
3539
3928
  "Capa",
3540
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3929
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3541
3930
  ZenitSelect,
3542
3931
  {
3543
3932
  ariaLabel: "Seleccionar capa para filtrar",
@@ -3550,9 +3939,9 @@ var ZenitLayerManager = ({
3550
3939
  }
3551
3940
  )
3552
3941
  ] }),
3553
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
3942
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
3554
3943
  "Campo",
3555
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3944
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3556
3945
  ZenitSelect,
3557
3946
  {
3558
3947
  ariaLabel: "Seleccionar campo de filtrado",
@@ -3565,34 +3954,31 @@ var ZenitLayerManager = ({
3565
3954
  }
3566
3955
  )
3567
3956
  ] }),
3568
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
3957
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, color: "#475569" }, children: [
3569
3958
  "Valor",
3570
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3571
- ZenitSelect,
3959
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3960
+ ZenitCombobox,
3572
3961
  {
3573
- ariaLabel: "Seleccionar valor de filtrado",
3574
3962
  value: selectedFilterValue,
3575
3963
  placeholder: "Seleccionar\u2026",
3576
- onValueChange: (nextValue) => setSelectedFilterValue(nextValue),
3577
- disabled: loadingCatalog || activeCatalogValues.length === 0,
3578
- options: activeCatalogValues.map((catalogValue) => ({
3579
- value: catalogValue,
3580
- label: catalogValue
3581
- }))
3964
+ searchPlaceholder: "Buscar valor\u2026",
3965
+ onChange: (nextValue) => setSelectedFilterValue(nextValue),
3966
+ options: activeCatalogValues,
3967
+ disabled: loadingCatalog || activeCatalogValues.length === 0
3582
3968
  }
3583
3969
  )
3584
3970
  ] }),
3585
- loadingCatalog && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { color: "#64748b", fontSize: 12 }, children: "Cargando cat\xE1logo\u2026" }),
3586
- !loadingCatalog && selectedFilterField && activeCatalogValues.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { color: "#64748b", fontSize: 12 }, children: "No hay cat\xE1logo disponible para este filtro." }),
3587
- filterError && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { color: "#b91c1c", fontSize: 12 }, children: filterError }),
3588
- appliedFilter && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "zlm-badge", style: { alignSelf: "flex-start" }, children: [
3971
+ loadingCatalog && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { color: "#64748b", fontSize: 12 }, children: "Cargando cat\xE1logo\u2026" }),
3972
+ !loadingCatalog && selectedFilterField && activeCatalogValues.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { color: "#64748b", fontSize: 12 }, children: "No hay cat\xE1logo disponible para este filtro." }),
3973
+ filterError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { color: "#b91c1c", fontSize: 12 }, children: filterError }),
3974
+ appliedFilter && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "zlm-badge", style: { alignSelf: "flex-start" }, children: [
3589
3975
  "Activo: ",
3590
3976
  appliedFilter.field,
3591
3977
  " = ",
3592
3978
  appliedFilter.value
3593
3979
  ] }),
3594
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "zlm-filter-actions", style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
3595
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3980
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "zlm-filter-actions", style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
3981
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3596
3982
  "button",
3597
3983
  {
3598
3984
  type: "button",
@@ -3602,7 +3988,7 @@ var ZenitLayerManager = ({
3602
3988
  children: applyingFilter ? "Aplicando\u2026" : "Aplicar"
3603
3989
  }
3604
3990
  ),
3605
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3991
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3606
3992
  "button",
3607
3993
  {
3608
3994
  type: "button",
@@ -3614,13 +4000,13 @@ var ZenitLayerManager = ({
3614
4000
  )
3615
4001
  ] })
3616
4002
  ] }) }),
3617
- showUploadTab && activeTab === "upload" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { color: "#475569", fontSize: 13 }, children: "Pr\xF3ximamente podr\xE1s subir capas desde este panel." })
4003
+ showUploadTab && activeTab === "upload" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { color: "#475569", fontSize: 13 }, children: "Pr\xF3ximamente podr\xE1s subir capas desde este panel." })
3618
4004
  ] })
3619
4005
  ] });
3620
4006
  };
3621
4007
 
3622
4008
  // src/react/ZenitFeatureFilterPanel.tsx
3623
- var import_jsx_runtime6 = require("react/jsx-runtime");
4009
+ var import_jsx_runtime7 = require("react/jsx-runtime");
3624
4010
  var ZenitFeatureFilterPanel = ({
3625
4011
  title = "Filtros",
3626
4012
  description,
@@ -3628,7 +4014,7 @@ var ZenitFeatureFilterPanel = ({
3628
4014
  style,
3629
4015
  children
3630
4016
  }) => {
3631
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
4017
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3632
4018
  "section",
3633
4019
  {
3634
4020
  className,
@@ -3641,22 +4027,22 @@ var ZenitFeatureFilterPanel = ({
3641
4027
  ...style
3642
4028
  },
3643
4029
  children: [
3644
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("header", { style: { marginBottom: 12 }, children: [
3645
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { style: { margin: 0, fontSize: 16 }, children: title }),
3646
- description && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: { margin: "6px 0 0", color: "#475569", fontSize: 13 }, children: description })
4030
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("header", { style: { marginBottom: 12 }, children: [
4031
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { style: { margin: 0, fontSize: 16 }, children: title }),
4032
+ description && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: { margin: "6px 0 0", color: "#475569", fontSize: 13 }, children: description })
3647
4033
  ] }),
3648
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children })
4034
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { children })
3649
4035
  ]
3650
4036
  }
3651
4037
  );
3652
4038
  };
3653
4039
 
3654
4040
  // src/react/ai/FloatingChatBox.tsx
3655
- var import_react9 = require("react");
4041
+ var import_react10 = require("react");
3656
4042
  var import_react_dom3 = require("react-dom");
3657
4043
 
3658
4044
  // src/react/hooks/use-chat.ts
3659
- var import_react8 = require("react");
4045
+ var import_react9 = require("react");
3660
4046
 
3661
4047
  // src/ai/chat.service.ts
3662
4048
  var DEFAULT_ERROR_MESSAGE = "No fue posible completar la solicitud al asistente.";
@@ -3788,9 +4174,9 @@ var sendMessageStream = async (mapId, request, callbacks = {}, options, config)
3788
4174
 
3789
4175
  // src/react/hooks/use-chat.ts
3790
4176
  var useSendMessage = (config) => {
3791
- const [isLoading, setIsLoading] = (0, import_react8.useState)(false);
3792
- const [error, setError] = (0, import_react8.useState)(null);
3793
- const send = (0, import_react8.useCallback)(
4177
+ const [isLoading, setIsLoading] = (0, import_react9.useState)(false);
4178
+ const [error, setError] = (0, import_react9.useState)(null);
4179
+ const send = (0, import_react9.useCallback)(
3794
4180
  async (mapId, request, options) => {
3795
4181
  setIsLoading(true);
3796
4182
  setError(null);
@@ -3808,18 +4194,18 @@ var useSendMessage = (config) => {
3808
4194
  return { sendMessage: send, isLoading, error };
3809
4195
  };
3810
4196
  var useSendMessageStream = (config) => {
3811
- const [isStreaming, setIsStreaming] = (0, import_react8.useState)(false);
3812
- const [streamingText, setStreamingText] = (0, import_react8.useState)("");
3813
- const [completeResponse, setCompleteResponse] = (0, import_react8.useState)(null);
3814
- const [error, setError] = (0, import_react8.useState)(null);
3815
- const requestIdRef = (0, import_react8.useRef)(0);
3816
- const reset = (0, import_react8.useCallback)(() => {
4197
+ const [isStreaming, setIsStreaming] = (0, import_react9.useState)(false);
4198
+ const [streamingText, setStreamingText] = (0, import_react9.useState)("");
4199
+ const [completeResponse, setCompleteResponse] = (0, import_react9.useState)(null);
4200
+ const [error, setError] = (0, import_react9.useState)(null);
4201
+ const requestIdRef = (0, import_react9.useRef)(0);
4202
+ const reset = (0, import_react9.useCallback)(() => {
3817
4203
  setIsStreaming(false);
3818
4204
  setStreamingText("");
3819
4205
  setCompleteResponse(null);
3820
4206
  setError(null);
3821
4207
  }, []);
3822
- const send = (0, import_react8.useCallback)(
4208
+ const send = (0, import_react9.useCallback)(
3823
4209
  async (mapId, request, options) => {
3824
4210
  const requestId = requestIdRef.current + 1;
3825
4211
  requestIdRef.current = requestId;
@@ -3873,7 +4259,7 @@ var useSendMessageStream = (config) => {
3873
4259
  // src/react/components/MarkdownRenderer.tsx
3874
4260
  var import_react_markdown = __toESM(require("react-markdown"));
3875
4261
  var import_remark_gfm = __toESM(require("remark-gfm"));
3876
- var import_jsx_runtime7 = require("react/jsx-runtime");
4262
+ var import_jsx_runtime8 = require("react/jsx-runtime");
3877
4263
  function normalizeAssistantMarkdown(text) {
3878
4264
  if (!text || typeof text !== "string") return "";
3879
4265
  let normalized = text;
@@ -3889,28 +4275,28 @@ var MarkdownRenderer = ({ content, className }) => {
3889
4275
  if (!normalizedContent) {
3890
4276
  return null;
3891
4277
  }
3892
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className, style: { wordBreak: "break-word" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4278
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className, style: { wordBreak: "break-word" }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3893
4279
  import_react_markdown.default,
3894
4280
  {
3895
4281
  remarkPlugins: [import_remark_gfm.default],
3896
4282
  components: {
3897
4283
  // Headings with proper spacing
3898
- h1: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { style: { fontSize: "1.5em", fontWeight: 700, marginTop: "1em", marginBottom: "0.5em" }, ...props, children }),
3899
- h2: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { style: { fontSize: "1.3em", fontWeight: 700, marginTop: "0.9em", marginBottom: "0.45em" }, ...props, children }),
3900
- h3: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { style: { fontSize: "1.15em", fontWeight: 600, marginTop: "0.75em", marginBottom: "0.4em" }, ...props, children }),
3901
- h4: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h4", { style: { fontSize: "1.05em", fontWeight: 600, marginTop: "0.6em", marginBottom: "0.35em" }, ...props, children }),
3902
- h5: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h5", { style: { fontSize: "1em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
3903
- h6: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h6", { style: { fontSize: "0.95em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
4284
+ h1: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h1", { style: { fontSize: "1.5em", fontWeight: 700, marginTop: "1em", marginBottom: "0.5em" }, ...props, children }),
4285
+ h2: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { style: { fontSize: "1.3em", fontWeight: 700, marginTop: "0.9em", marginBottom: "0.45em" }, ...props, children }),
4286
+ h3: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { style: { fontSize: "1.15em", fontWeight: 600, marginTop: "0.75em", marginBottom: "0.4em" }, ...props, children }),
4287
+ h4: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { style: { fontSize: "1.05em", fontWeight: 600, marginTop: "0.6em", marginBottom: "0.35em" }, ...props, children }),
4288
+ h5: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h5", { style: { fontSize: "1em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
4289
+ h6: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h6", { style: { fontSize: "0.95em", fontWeight: 600, marginTop: "0.5em", marginBottom: "0.3em" }, ...props, children }),
3904
4290
  // Paragraphs with comfortable line height
3905
- p: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: { marginTop: "0.5em", marginBottom: "0.5em", lineHeight: 1.6 }, ...props, children }),
4291
+ p: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: { marginTop: "0.5em", marginBottom: "0.5em", lineHeight: 1.6 }, ...props, children }),
3906
4292
  // Lists with proper indentation
3907
- ul: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
3908
- ol: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ol", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
3909
- li: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("li", { style: { marginTop: "0.25em", marginBottom: "0.25em" }, ...props, children }),
4293
+ ul: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
4294
+ ol: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ol", { style: { paddingLeft: "1.5em", marginTop: "0.5em", marginBottom: "0.5em" }, ...props, children }),
4295
+ li: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("li", { style: { marginTop: "0.25em", marginBottom: "0.25em" }, ...props, children }),
3910
4296
  // Code blocks
3911
4297
  code: ({ inline, children, ...props }) => {
3912
4298
  if (inline) {
3913
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4299
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3914
4300
  "code",
3915
4301
  {
3916
4302
  style: {
@@ -3925,7 +4311,7 @@ var MarkdownRenderer = ({ content, className }) => {
3925
4311
  }
3926
4312
  );
3927
4313
  }
3928
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4314
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3929
4315
  "code",
3930
4316
  {
3931
4317
  style: {
@@ -3945,9 +4331,9 @@ var MarkdownRenderer = ({ content, className }) => {
3945
4331
  );
3946
4332
  },
3947
4333
  // Pre (code block wrapper)
3948
- pre: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("pre", { style: { margin: 0 }, ...props, children }),
4334
+ pre: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("pre", { style: { margin: 0 }, ...props, children }),
3949
4335
  // Blockquotes
3950
- blockquote: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4336
+ blockquote: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3951
4337
  "blockquote",
3952
4338
  {
3953
4339
  style: {
@@ -3963,11 +4349,11 @@ var MarkdownRenderer = ({ content, className }) => {
3963
4349
  }
3964
4350
  ),
3965
4351
  // Strong/bold
3966
- strong: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { style: { fontWeight: 600 }, ...props, children }),
4352
+ strong: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { style: { fontWeight: 600 }, ...props, children }),
3967
4353
  // Emphasis/italic
3968
- em: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("em", { style: { fontStyle: "italic" }, ...props, children }),
4354
+ em: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("em", { style: { fontStyle: "italic" }, ...props, children }),
3969
4355
  // Horizontal rule
3970
- hr: (props) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4356
+ hr: (props) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3971
4357
  "hr",
3972
4358
  {
3973
4359
  style: {
@@ -3980,7 +4366,7 @@ var MarkdownRenderer = ({ content, className }) => {
3980
4366
  }
3981
4367
  ),
3982
4368
  // Tables (GFM)
3983
- table: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { overflowX: "auto", marginTop: "0.5em", marginBottom: "0.5em" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4369
+ table: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { overflowX: "auto", marginTop: "0.5em", marginBottom: "0.5em" }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3984
4370
  "table",
3985
4371
  {
3986
4372
  style: {
@@ -3992,7 +4378,7 @@ var MarkdownRenderer = ({ content, className }) => {
3992
4378
  children
3993
4379
  }
3994
4380
  ) }),
3995
- th: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4381
+ th: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3996
4382
  "th",
3997
4383
  {
3998
4384
  style: {
@@ -4006,7 +4392,7 @@ var MarkdownRenderer = ({ content, className }) => {
4006
4392
  children
4007
4393
  }
4008
4394
  ),
4009
- td: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4395
+ td: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4010
4396
  "td",
4011
4397
  {
4012
4398
  style: {
@@ -4024,32 +4410,32 @@ var MarkdownRenderer = ({ content, className }) => {
4024
4410
  };
4025
4411
 
4026
4412
  // src/react/ai/FloatingChatBox.tsx
4027
- var import_jsx_runtime8 = require("react/jsx-runtime");
4028
- var ChatIcon = () => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
4029
- var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4030
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
4031
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
4413
+ var import_jsx_runtime9 = require("react/jsx-runtime");
4414
+ var ChatIcon = () => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
4415
+ var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4416
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
4417
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
4032
4418
  ] });
4033
- var ExpandIcon = () => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4034
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "15 3 21 3 21 9" }),
4035
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "9 21 3 21 3 15" }),
4036
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
4037
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
4419
+ var ExpandIcon = () => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4420
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "15 3 21 3 21 9" }),
4421
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "9 21 3 21 3 15" }),
4422
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
4423
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
4038
4424
  ] });
4039
- var CollapseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4040
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "4 14 10 14 10 20" }),
4041
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "20 10 14 10 14 4" }),
4042
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
4043
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
4425
+ var CollapseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4426
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "4 14 10 14 10 20" }),
4427
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "20 10 14 10 14 4" }),
4428
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
4429
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
4044
4430
  ] });
4045
- var SendIcon = () => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4046
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
4047
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
4431
+ var SendIcon = () => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4432
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
4433
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
4048
4434
  ] });
4049
- var LayersIcon = () => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4050
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
4051
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "2 17 12 22 22 17" }),
4052
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "2 12 12 17 22 12" })
4435
+ var LayersIcon = () => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4436
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
4437
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "2 17 12 22 22 17" }),
4438
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "2 12 12 17 22 12" })
4053
4439
  ] });
4054
4440
  var styles = {
4055
4441
  root: {
@@ -4354,42 +4740,42 @@ var FloatingChatBox = ({
4354
4740
  open: openProp
4355
4741
  }) => {
4356
4742
  const isControlled = openProp !== void 0;
4357
- const [internalOpen, setInternalOpen] = (0, import_react9.useState)(false);
4743
+ const [internalOpen, setInternalOpen] = (0, import_react10.useState)(false);
4358
4744
  const open = isControlled ? openProp : internalOpen;
4359
- const setOpen = (0, import_react9.useCallback)((value) => {
4745
+ const setOpen = (0, import_react10.useCallback)((value) => {
4360
4746
  const newValue = typeof value === "function" ? value(open) : value;
4361
4747
  if (!isControlled) {
4362
4748
  setInternalOpen(newValue);
4363
4749
  }
4364
4750
  onOpenChange?.(newValue);
4365
4751
  }, [isControlled, open, onOpenChange]);
4366
- const [expanded, setExpanded] = (0, import_react9.useState)(false);
4367
- const [messages, setMessages] = (0, import_react9.useState)([]);
4368
- const [inputValue, setInputValue] = (0, import_react9.useState)("");
4369
- const [conversationId, setConversationId] = (0, import_react9.useState)();
4370
- const [errorMessage, setErrorMessage] = (0, import_react9.useState)(null);
4371
- const [isFocused, setIsFocused] = (0, import_react9.useState)(false);
4372
- const [isMobile, setIsMobile] = (0, import_react9.useState)(false);
4373
- const messagesEndRef = (0, import_react9.useRef)(null);
4374
- const messagesContainerRef = (0, import_react9.useRef)(null);
4375
- const chatBoxRef = (0, import_react9.useRef)(null);
4376
- const chatConfig = (0, import_react9.useMemo)(() => {
4752
+ const [expanded, setExpanded] = (0, import_react10.useState)(false);
4753
+ const [messages, setMessages] = (0, import_react10.useState)([]);
4754
+ const [inputValue, setInputValue] = (0, import_react10.useState)("");
4755
+ const [conversationId, setConversationId] = (0, import_react10.useState)();
4756
+ const [errorMessage, setErrorMessage] = (0, import_react10.useState)(null);
4757
+ const [isFocused, setIsFocused] = (0, import_react10.useState)(false);
4758
+ const [isMobile, setIsMobile] = (0, import_react10.useState)(false);
4759
+ const messagesEndRef = (0, import_react10.useRef)(null);
4760
+ const messagesContainerRef = (0, import_react10.useRef)(null);
4761
+ const chatBoxRef = (0, import_react10.useRef)(null);
4762
+ const chatConfig = (0, import_react10.useMemo)(() => {
4377
4763
  if (!baseUrl) return void 0;
4378
4764
  return { baseUrl, accessToken, getAccessToken };
4379
4765
  }, [accessToken, baseUrl, getAccessToken]);
4380
4766
  const { sendMessage: sendMessage2, isStreaming, streamingText, completeResponse } = useSendMessageStream(chatConfig);
4381
4767
  const canSend = Boolean(mapId) && Boolean(baseUrl) && inputValue.trim().length > 0 && !isStreaming;
4382
- (0, import_react9.useEffect)(() => {
4768
+ (0, import_react10.useEffect)(() => {
4383
4769
  if (open && isMobile) {
4384
4770
  setExpanded(true);
4385
4771
  }
4386
4772
  }, [open, isMobile]);
4387
- const scrollToBottom = (0, import_react9.useCallback)(() => {
4773
+ const scrollToBottom = (0, import_react10.useCallback)(() => {
4388
4774
  if (messagesEndRef.current) {
4389
4775
  messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
4390
4776
  }
4391
4777
  }, []);
4392
- (0, import_react9.useEffect)(() => {
4778
+ (0, import_react10.useEffect)(() => {
4393
4779
  if (open && messages.length === 0) {
4394
4780
  setMessages([
4395
4781
  {
@@ -4400,10 +4786,10 @@ var FloatingChatBox = ({
4400
4786
  ]);
4401
4787
  }
4402
4788
  }, [open, messages.length]);
4403
- (0, import_react9.useEffect)(() => {
4789
+ (0, import_react10.useEffect)(() => {
4404
4790
  scrollToBottom();
4405
4791
  }, [messages, streamingText, scrollToBottom]);
4406
- (0, import_react9.useEffect)(() => {
4792
+ (0, import_react10.useEffect)(() => {
4407
4793
  if (!open) return;
4408
4794
  if (isMobile && expanded) return;
4409
4795
  const handleClickOutside = (event) => {
@@ -4416,7 +4802,7 @@ var FloatingChatBox = ({
4416
4802
  document.removeEventListener("mousedown", handleClickOutside);
4417
4803
  };
4418
4804
  }, [open, isMobile, expanded]);
4419
- (0, import_react9.useEffect)(() => {
4805
+ (0, import_react10.useEffect)(() => {
4420
4806
  if (typeof window === "undefined") return;
4421
4807
  const mediaQuery = window.matchMedia("(max-width: 768px)");
4422
4808
  const updateMobile = () => setIsMobile(mediaQuery.matches);
@@ -4434,7 +4820,7 @@ var FloatingChatBox = ({
4434
4820
  }
4435
4821
  };
4436
4822
  }, []);
4437
- (0, import_react9.useEffect)(() => {
4823
+ (0, import_react10.useEffect)(() => {
4438
4824
  if (typeof document === "undefined") return;
4439
4825
  if (!open || !isMobile) return;
4440
4826
  document.body.style.overflow = "hidden";
@@ -4442,10 +4828,10 @@ var FloatingChatBox = ({
4442
4828
  document.body.style.overflow = "";
4443
4829
  };
4444
4830
  }, [open, isMobile]);
4445
- const addMessage = (0, import_react9.useCallback)((message) => {
4831
+ const addMessage = (0, import_react10.useCallback)((message) => {
4446
4832
  setMessages((prev) => [...prev, message]);
4447
4833
  }, []);
4448
- const handleSend = (0, import_react9.useCallback)(async () => {
4834
+ const handleSend = (0, import_react10.useCallback)(async () => {
4449
4835
  if (!mapId) {
4450
4836
  setErrorMessage("Selecciona un mapa para usar el asistente.");
4451
4837
  return;
@@ -4498,7 +4884,7 @@ var FloatingChatBox = ({
4498
4884
  sendMessage2,
4499
4885
  userId
4500
4886
  ]);
4501
- const handleKeyDown = (0, import_react9.useCallback)(
4887
+ const handleKeyDown = (0, import_react10.useCallback)(
4502
4888
  (event) => {
4503
4889
  if (event.key === "Enter" && !event.shiftKey) {
4504
4890
  event.preventDefault();
@@ -4509,20 +4895,20 @@ var FloatingChatBox = ({
4509
4895
  },
4510
4896
  [canSend, handleSend]
4511
4897
  );
4512
- const handleFollowUpClick = (0, import_react9.useCallback)((question) => {
4898
+ const handleFollowUpClick = (0, import_react10.useCallback)((question) => {
4513
4899
  setInputValue(question);
4514
4900
  }, []);
4515
4901
  const renderMetadata = (response) => {
4516
4902
  if (!response?.metadata) return null;
4517
4903
  const referencedLayers = response.metadata.referencedLayers;
4518
4904
  if (!referencedLayers || referencedLayers.length === 0) return null;
4519
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.metadataSection, children: [
4520
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.metadataTitle, children: [
4521
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(LayersIcon, {}),
4905
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.metadataSection, children: [
4906
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.metadataTitle, children: [
4907
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LayersIcon, {}),
4522
4908
  "Capas Analizadas"
4523
4909
  ] }),
4524
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { style: styles.metadataList, children: referencedLayers.map((layer, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { style: styles.metadataItem, children: [
4525
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { children: layer.layerName }),
4910
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { style: styles.metadataList, children: referencedLayers.map((layer, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("li", { style: styles.metadataItem, children: [
4911
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: layer.layerName }),
4526
4912
  " (",
4527
4913
  layer.featureCount,
4528
4914
  " ",
@@ -4531,7 +4917,7 @@ var FloatingChatBox = ({
4531
4917
  ] }, index)) })
4532
4918
  ] });
4533
4919
  };
4534
- const handleActionClick = (0, import_react9.useCallback)((action) => {
4920
+ const handleActionClick = (0, import_react10.useCallback)((action) => {
4535
4921
  if (isStreaming) return;
4536
4922
  setOpen(false);
4537
4923
  requestAnimationFrame(() => {
@@ -4540,9 +4926,9 @@ var FloatingChatBox = ({
4540
4926
  }, [isStreaming, setOpen, onActionClick]);
4541
4927
  const renderActions = (response) => {
4542
4928
  if (!response?.suggestedActions?.length) return null;
4543
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.actionsSection, children: [
4544
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: styles.sectionLabel, children: "Acciones Sugeridas" }),
4545
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: styles.actionsGrid, children: response.suggestedActions.map((action, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4929
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.actionsSection, children: [
4930
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.sectionLabel, children: "Acciones Sugeridas" }),
4931
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.actionsGrid, children: response.suggestedActions.map((action, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4546
4932
  "button",
4547
4933
  {
4548
4934
  type: "button",
@@ -4573,9 +4959,9 @@ var FloatingChatBox = ({
4573
4959
  };
4574
4960
  const renderFollowUps = (response) => {
4575
4961
  if (!response?.followUpQuestions?.length) return null;
4576
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.actionsSection, children: [
4577
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: styles.sectionLabel, children: "Preguntas Relacionadas" }),
4578
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: response.followUpQuestions.map((question, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4962
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.actionsSection, children: [
4963
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.sectionLabel, children: "Preguntas Relacionadas" }),
4964
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: response.followUpQuestions.map((question, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4579
4965
  "button",
4580
4966
  {
4581
4967
  type: "button",
@@ -4604,8 +4990,8 @@ var FloatingChatBox = ({
4604
4990
  )) })
4605
4991
  ] });
4606
4992
  };
4607
- const chatContent = /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.root, children: [
4608
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("style", { children: `
4993
+ const chatContent = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.root, children: [
4994
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("style", { children: `
4609
4995
  @keyframes zenitBlink {
4610
4996
  0%, 49% { opacity: 1; }
4611
4997
  50%, 100% { opacity: 0; }
@@ -4661,7 +5047,7 @@ var FloatingChatBox = ({
4661
5047
  }
4662
5048
  }
4663
5049
  ` }),
4664
- open && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
5050
+ open && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
4665
5051
  "div",
4666
5052
  {
4667
5053
  ref: chatBoxRef,
@@ -4675,10 +5061,10 @@ var FloatingChatBox = ({
4675
5061
  };
4676
5062
  })(),
4677
5063
  children: [
4678
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("header", { style: styles.header, children: [
4679
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { style: styles.title, children: "Asistente Zenit AI" }),
4680
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.headerButtons, children: [
4681
- !isMobile && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5064
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("header", { style: styles.header, children: [
5065
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { style: styles.title, children: "Asistente Zenit AI" }),
5066
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.headerButtons, children: [
5067
+ !isMobile && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4682
5068
  "button",
4683
5069
  {
4684
5070
  type: "button",
@@ -4691,10 +5077,10 @@ var FloatingChatBox = ({
4691
5077
  e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
4692
5078
  },
4693
5079
  "aria-label": expanded ? "Contraer" : "Expandir",
4694
- children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CollapseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ExpandIcon, {})
5080
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CollapseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ExpandIcon, {})
4695
5081
  }
4696
5082
  ),
4697
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5083
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4698
5084
  "button",
4699
5085
  {
4700
5086
  type: "button",
@@ -4707,20 +5093,20 @@ var FloatingChatBox = ({
4707
5093
  e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
4708
5094
  },
4709
5095
  "aria-label": "Cerrar",
4710
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CloseIcon, {})
5096
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CloseIcon, {})
4711
5097
  }
4712
5098
  )
4713
5099
  ] })
4714
5100
  ] }),
4715
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { ref: messagesContainerRef, className: "zenit-ai-body", style: styles.messages, children: [
4716
- messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5101
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { ref: messagesContainerRef, className: "zenit-ai-body", style: styles.messages, children: [
5102
+ messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4717
5103
  "div",
4718
5104
  {
4719
5105
  style: {
4720
5106
  ...styles.messageWrapper,
4721
5107
  alignItems: message.role === "user" ? "flex-end" : "flex-start"
4722
5108
  },
4723
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
5109
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
4724
5110
  "div",
4725
5111
  {
4726
5112
  style: {
@@ -4728,7 +5114,7 @@ var FloatingChatBox = ({
4728
5114
  ...message.role === "user" ? styles.userMessage : styles.assistantMessage
4729
5115
  },
4730
5116
  children: [
4731
- message.role === "assistant" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MarkdownRenderer, { content: message.content }) : message.content,
5117
+ message.role === "assistant" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MarkdownRenderer, { content: message.content }) : message.content,
4732
5118
  message.role === "assistant" && renderMetadata(message.response),
4733
5119
  message.role === "assistant" && renderActions(message.response),
4734
5120
  message.role === "assistant" && renderFollowUps(message.response)
@@ -4738,39 +5124,39 @@ var FloatingChatBox = ({
4738
5124
  },
4739
5125
  message.id
4740
5126
  )),
4741
- isStreaming && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5127
+ isStreaming && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4742
5128
  "div",
4743
5129
  {
4744
5130
  style: {
4745
5131
  ...styles.messageWrapper,
4746
5132
  alignItems: "flex-start"
4747
5133
  },
4748
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5134
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4749
5135
  "div",
4750
5136
  {
4751
5137
  style: {
4752
5138
  ...styles.messageBubble,
4753
5139
  ...styles.assistantMessage
4754
5140
  },
4755
- children: streamingText ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
4756
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MarkdownRenderer, { content: streamingText }),
4757
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.cursor })
4758
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.thinkingText, children: [
4759
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Pensando" }),
4760
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.typingIndicator, children: [
4761
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
4762
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
4763
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot })
5141
+ children: streamingText ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
5142
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MarkdownRenderer, { content: streamingText }),
5143
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.cursor })
5144
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.thinkingText, children: [
5145
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Pensando" }),
5146
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.typingIndicator, children: [
5147
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
5148
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot }),
5149
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "zenit-typing-dot", style: styles.typingDot })
4764
5150
  ] })
4765
5151
  ] })
4766
5152
  }
4767
5153
  )
4768
5154
  }
4769
5155
  ),
4770
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { ref: messagesEndRef })
5156
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { ref: messagesEndRef })
4771
5157
  ] }),
4772
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "zenit-ai-input-area", style: styles.inputWrapper, children: [
4773
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5158
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "zenit-ai-input-area", style: styles.inputWrapper, children: [
5159
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4774
5160
  "textarea",
4775
5161
  {
4776
5162
  style: {
@@ -4787,7 +5173,7 @@ var FloatingChatBox = ({
4787
5173
  disabled: !mapId || !baseUrl || isStreaming
4788
5174
  }
4789
5175
  ),
4790
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5176
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4791
5177
  "button",
4792
5178
  {
4793
5179
  type: "button",
@@ -4796,18 +5182,18 @@ var FloatingChatBox = ({
4796
5182
  onClick: () => void handleSend(),
4797
5183
  disabled: !canSend,
4798
5184
  "aria-label": "Enviar mensaje",
4799
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SendIcon, {})
5185
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SendIcon, {})
4800
5186
  }
4801
5187
  )
4802
5188
  ] }),
4803
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: styles.errorText, children: errorMessage }),
4804
- isStreaming && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: styles.statusNote, children: "Generando sugerencias..." }),
4805
- !mapId && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: styles.statusNote, children: "Selecciona un mapa para usar el asistente" }),
4806
- !baseUrl && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: styles.statusNote, children: "Configura la baseUrl del SDK" })
5189
+ errorMessage && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.errorText, children: errorMessage }),
5190
+ isStreaming && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.statusNote, children: "Generando sugerencias..." }),
5191
+ !mapId && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.statusNote, children: "Selecciona un mapa para usar el asistente" }),
5192
+ !baseUrl && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.statusNote, children: "Configura la baseUrl del SDK" })
4807
5193
  ]
4808
5194
  }
4809
5195
  ),
4810
- !(hideButton && !open) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5196
+ !(hideButton && !open) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4811
5197
  "button",
4812
5198
  {
4813
5199
  type: "button",
@@ -4819,9 +5205,9 @@ var FloatingChatBox = ({
4819
5205
  },
4820
5206
  onClick: () => setOpen((prev) => !prev),
4821
5207
  "aria-label": open ? "Cerrar asistente" : "Abrir asistente Zenit AI",
4822
- children: open ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CloseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
4823
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChatIcon, {}),
4824
- !isMobile && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Asistente IA" })
5208
+ children: open ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CloseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
5209
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ChatIcon, {}),
5210
+ !isMobile && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Asistente IA" })
4825
5211
  ] })
4826
5212
  }
4827
5213
  )