@dynatrace/strato-geo 3.6.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/esm/map/MapView.js +42 -34
  2. package/esm/map/MapView.js.map +2 -2
  3. package/esm/map/components/BubbleLayer/BubbleCircleLayer.js +2 -0
  4. package/esm/map/components/BubbleLayer/BubbleCircleLayer.js.map +2 -2
  5. package/esm/map/components/BubbleLayer/BubbleLayer.js +4 -1
  6. package/esm/map/components/BubbleLayer/BubbleLayer.js.map +2 -2
  7. package/esm/map/components/BubbleLayer/utils/parse-bubble-data-to-geo-json.js +5 -5
  8. package/esm/map/components/BubbleLayer/utils/parse-bubble-data-to-geo-json.js.map +2 -2
  9. package/esm/map/components/ChoroplethLayer/ChoroplethLayer.js +5 -2
  10. package/esm/map/components/ChoroplethLayer/ChoroplethLayer.js.map +2 -2
  11. package/esm/map/components/ChoroplethLayer/ChoroplethLayerTooltip.js.map +2 -2
  12. package/esm/map/components/ChoroplethLayer/ChoroplethOutlineLayer.js +3 -1
  13. package/esm/map/components/ChoroplethLayer/ChoroplethOutlineLayer.js.map +2 -2
  14. package/esm/map/components/ChoroplethLayer/utils/parse-region-data-to-geo-json.js +6 -5
  15. package/esm/map/components/ChoroplethLayer/utils/parse-region-data-to-geo-json.js.map +2 -2
  16. package/esm/map/components/ConnectionLayer/ConnectionLayer.js +1 -1
  17. package/esm/map/components/ConnectionLayer/ConnectionLayer.js.map +2 -2
  18. package/esm/map/components/ConnectionLayer/ConnectionLayerLine.js +3 -0
  19. package/esm/map/components/ConnectionLayer/ConnectionLayerLine.js.map +2 -2
  20. package/esm/map/components/ConnectionLayer/ConnectionLayerTooltip.js +7 -9
  21. package/esm/map/components/ConnectionLayer/ConnectionLayerTooltip.js.map +2 -2
  22. package/esm/map/components/ConnectionLayer/utils/parse-connection-data-to-geo-json.js +20 -18
  23. package/esm/map/components/ConnectionLayer/utils/parse-connection-data-to-geo-json.js.map +2 -2
  24. package/esm/map/components/DotLayer/DotLayer.js +4 -1
  25. package/esm/map/components/DotLayer/DotLayer.js.map +2 -2
  26. package/esm/map/components/DotLayer/DotLayerTooltip.js.map +2 -2
  27. package/esm/map/components/DotLayer/utils/parse-dot-data-to-geo-json.js +5 -5
  28. package/esm/map/components/DotLayer/utils/parse-dot-data-to-geo-json.js.map +2 -2
  29. package/esm/map/components/MapContent.js +22 -12
  30. package/esm/map/components/MapContent.js.map +2 -2
  31. package/esm/map/contexts/geo-data-lookup.context.js +8 -0
  32. package/esm/map/contexts/geo-data-lookup.context.js.map +7 -0
  33. package/esm/map/hooks/use-active-interaction.js +59 -43
  34. package/esm/map/hooks/use-active-interaction.js.map +2 -2
  35. package/esm/map/hooks/use-attach-image-from-icon.js +4 -2
  36. package/esm/map/hooks/use-attach-image-from-icon.js.map +2 -2
  37. package/esm/map/hooks/use-hover-interaction.js +59 -41
  38. package/esm/map/hooks/use-hover-interaction.js.map +2 -2
  39. package/esm/map/hooks/use-layer-before-id.js +24 -0
  40. package/esm/map/hooks/use-layer-before-id.js.map +7 -0
  41. package/esm/map/hooks/use-map-runtime-error.js +93 -0
  42. package/esm/map/hooks/use-map-runtime-error.js.map +7 -0
  43. package/esm/map/hooks/use-overlay-events.js +11 -2
  44. package/esm/map/hooks/use-overlay-events.js.map +2 -2
  45. package/esm/map/hooks/use-webgl-context-error.js +2 -1
  46. package/esm/map/hooks/use-webgl-context-error.js.map +2 -2
  47. package/esm/map/index.js.map +1 -1
  48. package/esm/map/slots/Tooltip.js.map +2 -2
  49. package/esm/map/utils/attach-image-from-shape.js +4 -2
  50. package/esm/map/utils/attach-image-from-shape.js.map +2 -2
  51. package/esm/map/utils/extract-layers-data.js +24 -15
  52. package/esm/map/utils/extract-layers-data.js.map +2 -2
  53. package/esm/map/utils/is-browser-firefox.js +7 -0
  54. package/esm/map/utils/is-browser-firefox.js.map +7 -0
  55. package/esm/map/utils/parse-tooltip-data.js +22 -7
  56. package/esm/map/utils/parse-tooltip-data.js.map +2 -2
  57. package/map/MapView.js +42 -34
  58. package/map/components/BubbleLayer/BubbleCircleLayer.d.ts +2 -1
  59. package/map/components/BubbleLayer/BubbleCircleLayer.js +2 -0
  60. package/map/components/BubbleLayer/BubbleLayer.js +4 -1
  61. package/map/components/BubbleLayer/utils/parse-bubble-data-to-geo-json.d.ts +3 -1
  62. package/map/components/BubbleLayer/utils/parse-bubble-data-to-geo-json.js +5 -5
  63. package/map/components/ChoroplethLayer/ChoroplethLayer.js +5 -2
  64. package/map/components/ChoroplethLayer/ChoroplethOutlineLayer.d.ts +1 -0
  65. package/map/components/ChoroplethLayer/ChoroplethOutlineLayer.js +3 -1
  66. package/map/components/ChoroplethLayer/utils/parse-region-data-to-geo-json.d.ts +3 -1
  67. package/map/components/ChoroplethLayer/utils/parse-region-data-to-geo-json.js +6 -5
  68. package/map/components/ConnectionLayer/ConnectionLayer.js +1 -1
  69. package/map/components/ConnectionLayer/ConnectionLayerLine.js +3 -0
  70. package/map/components/ConnectionLayer/ConnectionLayerTooltip.js +7 -9
  71. package/map/components/ConnectionLayer/utils/parse-connection-data-to-geo-json.d.ts +3 -1
  72. package/map/components/ConnectionLayer/utils/parse-connection-data-to-geo-json.js +20 -18
  73. package/map/components/DotLayer/DotLayer.js +4 -1
  74. package/map/components/DotLayer/utils/parse-dot-data-to-geo-json.d.ts +3 -1
  75. package/map/components/DotLayer/utils/parse-dot-data-to-geo-json.js +5 -5
  76. package/map/components/MapContent.js +21 -12
  77. package/map/contexts/geo-data-lookup.context.d.ts +9 -0
  78. package/map/{components/ConnectionLayer/utils/restore-null-props.js → contexts/geo-data-lookup.context.js} +8 -9
  79. package/map/hooks/use-active-interaction.d.ts +8 -1
  80. package/map/hooks/use-active-interaction.js +58 -42
  81. package/map/hooks/use-attach-image-from-icon.js +4 -2
  82. package/map/hooks/use-hover-interaction.d.ts +6 -2
  83. package/map/hooks/use-hover-interaction.js +52 -39
  84. package/map/hooks/use-layer-before-id.d.ts +13 -0
  85. package/map/hooks/{use-map-mouse-move.js → use-layer-before-id.js} +20 -15
  86. package/map/hooks/use-map-runtime-error.d.ts +34 -0
  87. package/map/hooks/use-map-runtime-error.js +112 -0
  88. package/map/hooks/use-overlay-events.js +11 -2
  89. package/map/hooks/use-webgl-context-error.js +2 -1
  90. package/map/slots/Tooltip.d.ts +2 -0
  91. package/map/types/connection-layer.d.ts +1 -8
  92. package/map/types/tooltip.d.ts +1 -0
  93. package/map/utils/attach-image-from-shape.js +4 -2
  94. package/map/utils/extract-layers-data.d.ts +2 -0
  95. package/map/utils/extract-layers-data.js +24 -15
  96. package/map/utils/is-browser-firefox.d.ts +5 -0
  97. package/map/utils/is-browser-firefox.js +26 -0
  98. package/map/utils/parse-tooltip-data.d.ts +11 -3
  99. package/map/utils/parse-tooltip-data.js +22 -7
  100. package/package.json +2 -2
  101. package/esm/map/components/ConnectionLayer/utils/restore-null-props.js +0 -9
  102. package/esm/map/components/ConnectionLayer/utils/restore-null-props.js.map +0 -7
  103. package/esm/map/hooks/use-map-mouse-move.js +0 -19
  104. package/esm/map/hooks/use-map-mouse-move.js.map +0 -7
  105. package/map/components/ConnectionLayer/utils/restore-null-props.d.ts +0 -2
  106. package/map/hooks/use-map-mouse-move.d.ts +0 -2
@@ -24,9 +24,16 @@ module.exports = __toCommonJS(use_hover_interaction_exports);
24
24
  var import_react_maplibre = require("@vis.gl/react-maplibre");
25
25
  var import_lodash_es = require("lodash");
26
26
  var import_react = require("react");
27
- var import_constants = require("../constants.js");
28
27
  var import_associated_features = require("../utils/associated-features.js");
29
28
  var import_get_min_value_feature = require("../utils/get-min-value-feature.js");
29
+ const MOUSEMOVE_THROTTLE_MS = 16;
30
+ const blurTrackedFeature = (map, featureIdRef, sourceIdRef) => {
31
+ if (!(0, import_lodash_es.isNil)(featureIdRef.current) && !(0, import_lodash_es.isNil)(sourceIdRef.current)) {
32
+ blurFeature(map, sourceIdRef.current, featureIdRef.current);
33
+ featureIdRef.current = void 0;
34
+ sourceIdRef.current = void 0;
35
+ }
36
+ };
30
37
  const featureExists = (map, source, id) => {
31
38
  const isSourcePresent = map.getSource(source) !== void 0;
32
39
  return isSourcePresent && map.getFeatureState({
@@ -68,53 +75,59 @@ const hoverFeature = (map, source, id) => {
68
75
  }
69
76
  }
70
77
  };
71
- const useHoverInteraction = () => {
78
+ const useHoverInteraction = (interactiveLayerIds) => {
72
79
  const map = (0, import_react_maplibre.useMap)().current;
73
- let featureId;
74
- let sourceId;
75
- const handleMouseOut = (0, import_react.useCallback)(
76
- ({ point }) => {
77
- if (!(0, import_lodash_es.isNil)(map) && !(0, import_lodash_es.isUndefined)(featureId) && !(0, import_lodash_es.isUndefined)(sourceId)) {
78
- blurFeature(map, sourceId, featureId);
79
- }
80
- },
81
- [featureId, sourceId, map]
82
- );
83
- const handleMouseMove = (0, import_react.useCallback)(
84
- ({ point }) => {
85
- if (!(0, import_lodash_es.isNil)(map)) {
86
- const features = map.queryRenderedFeatures(point).filter((feature) => !(0, import_associated_features.isAssociatedFeature)(feature.properties.id));
87
- map.getCanvas().style.cursor = "grab";
80
+ const featureIdRef = (0, import_react.useRef)(void 0);
81
+ const sourceIdRef = (0, import_react.useRef)(void 0);
82
+ const interactiveLayerIdsRef = (0, import_react.useRef)(interactiveLayerIds);
83
+ interactiveLayerIdsRef.current = interactiveLayerIds;
84
+ const handleMouseOut = (0, import_react.useCallback)(() => {
85
+ if (!(0, import_lodash_es.isNil)(map)) {
86
+ blurTrackedFeature(map, featureIdRef, sourceIdRef);
87
+ }
88
+ }, [map]);
89
+ const throttledMouseMove = (0, import_react.useMemo)(
90
+ () => (0, import_lodash_es.throttle)(
91
+ ({ point }) => {
92
+ if ((0, import_lodash_es.isNil)(map)) {
93
+ return;
94
+ }
95
+ let features;
96
+ try {
97
+ features = map.queryRenderedFeatures(point, {
98
+ layers: interactiveLayerIdsRef.current
99
+ }).filter((feature) => !(0, import_associated_features.isAssociatedFeature)(feature.properties.id));
100
+ } catch {
101
+ return;
102
+ }
88
103
  const layerId = features?.[0]?.layer?.id;
89
104
  const hasHoveredFeatures = !(0, import_lodash_es.isNil)(features) && features.length > 0 && !(0, import_lodash_es.isUndefined)(layerId);
90
- const isBaseLayer = import_constants.BASE_LAYER_IDS.includes(layerId);
91
- if (hasHoveredFeatures && !isBaseLayer) {
92
- map.getCanvas().style.cursor = "pointer";
93
- if (!(0, import_lodash_es.isUndefined)(featureId) && !(0, import_lodash_es.isUndefined)(sourceId)) {
94
- blurFeature(map, sourceId, featureId);
95
- }
96
- const minFeature = (0, import_get_min_value_feature.getMinValueFeature)(features);
97
- featureId = minFeature.id;
98
- sourceId = minFeature.layer.source;
99
- if (!(0, import_lodash_es.isUndefined)(featureId)) {
100
- hoverFeature(map, sourceId, featureId);
101
- }
102
- } else {
105
+ if (!hasHoveredFeatures) {
103
106
  map.getCanvas().style.cursor = "grab";
104
- if (!(0, import_lodash_es.isUndefined)(featureId) && !(0, import_lodash_es.isUndefined)(sourceId)) {
105
- blurFeature(map, sourceId, featureId);
106
- }
107
+ blurTrackedFeature(map, featureIdRef, sourceIdRef);
108
+ return;
107
109
  }
108
- }
109
- },
110
- [featureId, sourceId, map]
110
+ map.getCanvas().style.cursor = "pointer";
111
+ blurTrackedFeature(map, featureIdRef, sourceIdRef);
112
+ const minFeature = (0, import_get_min_value_feature.getMinValueFeature)(features);
113
+ featureIdRef.current = minFeature.id;
114
+ sourceIdRef.current = minFeature.layer.source;
115
+ if (!(0, import_lodash_es.isUndefined)(featureIdRef.current)) {
116
+ hoverFeature(map, sourceIdRef.current, featureIdRef.current);
117
+ }
118
+ },
119
+ MOUSEMOVE_THROTTLE_MS,
120
+ { trailing: true }
121
+ ),
122
+ [map]
111
123
  );
112
124
  (0, import_react.useEffect)(() => {
113
- map?.on("mousemove", handleMouseMove);
125
+ map?.on("mousemove", throttledMouseMove);
114
126
  map?.on("mouseout", handleMouseOut);
115
127
  return () => {
116
- map?.off("mousemove", handleMouseMove);
128
+ throttledMouseMove.cancel();
129
+ map?.off("mousemove", throttledMouseMove);
117
130
  map?.off("mouseout", handleMouseOut);
118
131
  };
119
- }, []);
132
+ }, [map, throttledMouseMove, handleMouseOut]);
120
133
  };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Returns the maplibre layer id that the current layer should be inserted before,
3
+ * based on the JSX order of `MapView` children.
4
+ *
5
+ * Without this, layers that mount asynchronously (e.g. `{apiData && <ChoroplethLayer>}`)
6
+ * are appended to the top of the maplibre stack and end up visually above siblings
7
+ * that mounted earlier — even when JSX puts them first. Passing the returned value as
8
+ * `beforeId` to a `<Layer>` keeps the rendered stack aligned with JSX order.
9
+ *
10
+ * Only returns an id that actually exists in the map right now, so the result is
11
+ * always safe to pass to `map.addLayer(opts, beforeId)`.
12
+ */
13
+ export declare const useLayerBeforeId: (layerId: string) => string | undefined;
@@ -16,23 +16,28 @@ var __copyProps = (to, from, except, desc) => {
16
16
  return to;
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var use_map_mouse_move_exports = {};
20
- __export(use_map_mouse_move_exports, {
21
- useMapMouseMove: () => useMapMouseMove
19
+ var use_layer_before_id_exports = {};
20
+ __export(use_layer_before_id_exports, {
21
+ useLayerBeforeId: () => useLayerBeforeId
22
22
  });
23
- module.exports = __toCommonJS(use_map_mouse_move_exports);
23
+ module.exports = __toCommonJS(use_layer_before_id_exports);
24
24
  var import_react_maplibre = require("@vis.gl/react-maplibre");
25
25
  var import_react = require("react");
26
- const useMapMouseMove = (layerIds, callback) => {
26
+ var import_layer_ids_context = require("../contexts/layer-ids.context.js");
27
+ const useLayerBeforeId = (layerId) => {
28
+ const layerIds = (0, import_react.useContext)(import_layer_ids_context.LayerIdsContext);
27
29
  const { current: map } = (0, import_react_maplibre.useMap)();
28
- (0, import_react.useEffect)(() => {
29
- layerIds.forEach((layerId) => {
30
- map?.on("mousemove", layerId, callback);
31
- });
32
- return () => {
33
- layerIds.forEach((layerId) => {
34
- map?.off("mousemove", layerId, callback);
35
- });
36
- };
37
- });
30
+ if (!map) {
31
+ return void 0;
32
+ }
33
+ const currentIndex = layerIds.indexOf(layerId);
34
+ if (currentIndex === -1) {
35
+ return void 0;
36
+ }
37
+ for (let i = currentIndex + 1; i < layerIds.length; i++) {
38
+ if (map.getLayer(layerIds[i])) {
39
+ return layerIds[i];
40
+ }
41
+ }
42
+ return void 0;
38
43
  };
@@ -0,0 +1,34 @@
1
+ export interface UseMapRuntimeErrorOptions {
2
+ /**
3
+ * Called when the retry budget (3 attempts) is exhausted and the map cannot
4
+ * recover. Throwing inside this callback will propagate to the nearest React
5
+ * ErrorBoundary, showing the fallback UI.
6
+ */
7
+ onError: () => void;
8
+ /**
9
+ * Optional callback invoked on each recoverable error attempt before the
10
+ * budget is exhausted. The `attempt` argument is 1-indexed.
11
+ */
12
+ onRetry?: (attempt: number) => void;
13
+ }
14
+ /**
15
+ * Unified hook that guards MapView against maplibre-gl runtime errors from
16
+ * three distinct sources:
17
+ *
18
+ * 1. **WebGL context loss** (`webglcontextlost` on the canvas) — composed via
19
+ * `useWebGLContextError`.
20
+ * 2. **maplibre's own error events** (`map.on('error', ...)`), covering tile
21
+ * load failures and other internally dispatched errors.
22
+ * 3. **Synchronous throws from the rAF render loop** that escape to
23
+ * `window.onerror` — shader compilation, program link, and feature-index
24
+ * out-of-bounds errors that maplibre does not catch internally.
25
+ *
26
+ * A shared retry counter (max 3) is maintained across all sources. Error
27
+ * counting is debounced at 500 ms so that a burst of errors within a single
28
+ * render frame counts as one occurrence. The counter resets whenever the map
29
+ * fires an `idle` event (indicating a successful render). Once the budget is
30
+ * exhausted, `onError` is invoked.
31
+ *
32
+ * APPDEV-17938
33
+ */
34
+ export declare const useMapRuntimeError: ({ onError, onRetry, }: UseMapRuntimeErrorOptions) => void;
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var use_map_runtime_error_exports = {};
20
+ __export(use_map_runtime_error_exports, {
21
+ useMapRuntimeError: () => useMapRuntimeError
22
+ });
23
+ module.exports = __toCommonJS(use_map_runtime_error_exports);
24
+ var import_react_maplibre = require("@vis.gl/react-maplibre");
25
+ var import_react = require("react");
26
+ var import_use_webgl_context_error = require("./use-webgl-context-error.js");
27
+ const MAX_RETRIES = 3;
28
+ const ERROR_DEBOUNCE_MS = 500;
29
+ const MAPLIBRE_RUNTIME_ERROR_PATTERNS = [
30
+ "Could not compile fragment shader",
31
+ "Could not compile vertex shader",
32
+ "Program failed to link",
33
+ "feature index out of bounds",
34
+ "Out of bounds. Index requested"
35
+ ];
36
+ const isMaplibreRuntimeError = (message) => MAPLIBRE_RUNTIME_ERROR_PATTERNS.some((pattern) => message.includes(pattern));
37
+ const useMapRuntimeError = ({
38
+ onError,
39
+ onRetry
40
+ }) => {
41
+ const { current: mapRef } = (0, import_react_maplibre.useMap)();
42
+ const retryCountRef = (0, import_react.useRef)(0);
43
+ const lastErrorTimeRef = (0, import_react.useRef)(0);
44
+ const isMapActiveRef = (0, import_react.useRef)(true);
45
+ const onErrorRef = (0, import_react.useRef)(onError);
46
+ onErrorRef.current = onError;
47
+ const onRetryRef = (0, import_react.useRef)(onRetry);
48
+ onRetryRef.current = onRetry;
49
+ const handleError = (0, import_react.useCallback)(() => {
50
+ const now = Date.now();
51
+ if (now - lastErrorTimeRef.current < ERROR_DEBOUNCE_MS) {
52
+ return;
53
+ }
54
+ lastErrorTimeRef.current = now;
55
+ retryCountRef.current += 1;
56
+ if (retryCountRef.current >= MAX_RETRIES) {
57
+ onErrorRef.current();
58
+ } else {
59
+ onRetryRef.current?.(retryCountRef.current);
60
+ }
61
+ }, []);
62
+ (0, import_use_webgl_context_error.useWebGLContextError)(handleError);
63
+ (0, import_react.useEffect)(() => {
64
+ const map = mapRef?.getMap();
65
+ if (!map) {
66
+ return;
67
+ }
68
+ const handleMapError = ({ error }) => {
69
+ if (isMaplibreRuntimeError(error.message)) {
70
+ handleError();
71
+ }
72
+ };
73
+ map.on("error", handleMapError);
74
+ return () => {
75
+ map.off("error", handleMapError);
76
+ };
77
+ }, [mapRef, handleError]);
78
+ (0, import_react.useEffect)(() => {
79
+ const handleWindowError = (event) => {
80
+ if (!isMapActiveRef.current) {
81
+ return;
82
+ }
83
+ if (isMaplibreRuntimeError(event.message)) {
84
+ event.preventDefault();
85
+ handleError();
86
+ }
87
+ };
88
+ window.addEventListener("error", handleWindowError);
89
+ return () => {
90
+ window.removeEventListener("error", handleWindowError);
91
+ };
92
+ }, [handleError]);
93
+ (0, import_react.useEffect)(() => {
94
+ const map = mapRef?.getMap();
95
+ if (!map) {
96
+ return;
97
+ }
98
+ const handleRender = () => {
99
+ isMapActiveRef.current = true;
100
+ };
101
+ const handleIdle = () => {
102
+ isMapActiveRef.current = false;
103
+ retryCountRef.current = 0;
104
+ };
105
+ map.on("render", handleRender);
106
+ map.on("idle", handleIdle);
107
+ return () => {
108
+ map.off("render", handleRender);
109
+ map.off("idle", handleIdle);
110
+ };
111
+ }, [mapRef]);
112
+ };
@@ -21,7 +21,9 @@ __export(use_overlay_events_exports, {
21
21
  useOverlayEvents: () => useOverlayEvents
22
22
  });
23
23
  module.exports = __toCommonJS(use_overlay_events_exports);
24
+ var import_react = require("react");
24
25
  var import_charts = require("@dynatrace/strato-components/charts");
26
+ var import_geo_data_lookup_context = require("../contexts/geo-data-lookup.context.js");
25
27
  var import_store = require("../store/store.js");
26
28
  var import_build_geo_tooltip_state = require("../utils/build-geo-tooltip-state.js");
27
29
  var import_parse_tooltip_data = require("../utils/parse-tooltip-data.js");
@@ -38,6 +40,7 @@ const layerIdToGeometry = (layerId) => {
38
40
  return "geoDot";
39
41
  };
40
42
  const useOverlayEvents = () => {
43
+ const dataLookupRegistry = (0, import_react.useContext)(import_geo_data_lookup_context.GeoDataLookupContext);
41
44
  const setOverlayState = (0, import_store.useSetStateOverlay)();
42
45
  const setState = (0, import_store.useSetState)();
43
46
  const dispatch = (0, import_charts._useOverlayTooltipReducer)();
@@ -72,7 +75,10 @@ const useOverlayEvents = () => {
72
75
  if (currentState.pinned) {
73
76
  return;
74
77
  }
75
- const { data, hoveredLayerId } = (0, import_parse_tooltip_data.extractDataFromEvent)(event);
78
+ const { data, hoveredLayerId } = (0, import_parse_tooltip_data.extractDataFromEvent)(
79
+ event,
80
+ dataLookupRegistry
81
+ );
76
82
  overlay.clear();
77
83
  setTooltipMarker(hoveredLayerId, event.lngLat);
78
84
  const pos = getAbsolutePosition(event);
@@ -102,7 +108,10 @@ const useOverlayEvents = () => {
102
108
  }
103
109
  };
104
110
  const handleMouseClick = (event) => {
105
- const { data, featureId, hoveredLayerId } = (0, import_parse_tooltip_data.extractDataFromEvent)(event);
111
+ const { data, featureId, hoveredLayerId } = (0, import_parse_tooltip_data.extractDataFromEvent)(
112
+ event,
113
+ dataLookupRegistry
114
+ );
106
115
  if (!featureId) {
107
116
  hideTooltip();
108
117
  return;
@@ -30,7 +30,8 @@ const useWebGLContextError = (onContextLost) => {
30
30
  if (!canvas) {
31
31
  return;
32
32
  }
33
- const handleContextLost = () => {
33
+ const handleContextLost = (event) => {
34
+ event.preventDefault();
34
35
  onContextLost?.();
35
36
  };
36
37
  canvas.addEventListener("webglcontextlost", handleContextLost);
@@ -4,11 +4,13 @@ import type { ChartTooltip } from '../types/tooltip.js';
4
4
  * Tooltip is responsible for exposing the
5
5
  * ChartTooltip props, such as, sections, to the consumer
6
6
  * @public
7
+ * @deprecated Use `ChartTooltip` from `@dynatrace/strato-components/charts` instead. Removal: APPDEV-17834
7
8
  */
8
9
  export declare const Tooltip: ChartTooltip;
9
10
  /**
10
11
  * TooltipAtoms is responsible for exposing the
11
12
  * ChartTooltip atoms.
12
13
  * @public
14
+ * @deprecated Use `ChartTooltip` from `@dynatrace/strato-components/charts` instead. Removal: APPDEV-17834
13
15
  */
14
16
  export declare const TooltipAtoms: ChartTooltipAtomsType;
@@ -53,12 +53,12 @@ export type InternalConnectionLayerProps<T extends Connection> = ConnectionLayer
53
53
  /** @internal */
54
54
  export interface FeatureProperties {
55
55
  id: string;
56
+ __dataIndex?: number;
56
57
  __lineColor: string;
57
58
  __lineHoveredColor: string;
58
59
  __lineWidth: number;
59
60
  __angle?: number;
60
61
  curve?: CurvedLine;
61
- path: Location[];
62
62
  }
63
63
  export type GeoJSONFeature<T extends GeoJSON.Geometry> = GeoJSON.Feature<T, FeatureProperties>;
64
64
  /**
@@ -79,10 +79,3 @@ export interface ConnectionColorProps<T extends Connection> {
79
79
  */
80
80
  color?: string | ((connection: T) => string);
81
81
  }
82
- /** @internal */
83
- export type ConnectionTooltipStatePayload = {
84
- path: Location[];
85
- __lineColor: string;
86
- __lineWidth: number;
87
- __nullValues: string[] | undefined;
88
- };
@@ -145,5 +145,6 @@ export interface ChoroplethLayerTooltipHandlerProps {
145
145
  /**
146
146
  * Map Geo Tooltip Props
147
147
  * @public
148
+ * @deprecated Use `ChartTooltip` from `@dynatrace/strato-components/charts` instead. Removal: APPDEV-17834
148
149
  */
149
150
  export type ChartTooltip = ChartTooltipSlotsType & ChartTooltipTemplateType;
@@ -25,20 +25,22 @@ var import_attach_image_to_map = require("./attach-image-to-map.js");
25
25
  var import_create_bitmap_config_options = require("./create-bitmap-config-options.js");
26
26
  var import_get_data_uri = require("./get-data-uri.js");
27
27
  var import_constants = require("../constants.js");
28
+ var import_is_browser_firefox = require("./is-browser-firefox.js");
28
29
  var import_shape_picker = require("../shapes/shape-picker.js");
29
30
  const attachImageFromShape = (map, shape, name, outputSize) => {
30
31
  const pickedShape = (0, import_shape_picker.getShape)(shape);
31
32
  const stringUrl = (0, import_get_data_uri.getDataUri)(encodeURIComponent(pickedShape));
32
33
  const img = new Image(import_constants.DEFAULT_INPUT_ICON_SIZE, import_constants.DEFAULT_INPUT_ICON_SIZE);
33
34
  img.addEventListener("load", () => {
34
- createImageBitmap(
35
+ const bitmapPromise = (0, import_is_browser_firefox.isFirefox)() ? createImageBitmap(img, (0, import_create_bitmap_config_options.createBitmapConfigOptions)(outputSize)) : createImageBitmap(
35
36
  img,
36
37
  0,
37
38
  0,
38
39
  import_constants.DEFAULT_INPUT_ICON_SIZE,
39
40
  import_constants.DEFAULT_INPUT_ICON_SIZE,
40
41
  (0, import_create_bitmap_config_options.createBitmapConfigOptions)(outputSize)
41
- ).then((bitmap) => {
42
+ );
43
+ bitmapPromise.then((bitmap) => {
42
44
  if (!map) {
43
45
  return;
44
46
  }
@@ -1,4 +1,5 @@
1
1
  import { type ReactNode } from 'react';
2
+ import type { GeoDataLookupRegistry } from '../contexts/geo-data-lookup.context.js';
2
3
  /**
3
4
  * Extract layers data
4
5
  * @param children - MapView children
@@ -9,4 +10,5 @@ export declare const extractLayersData: (children: ReactNode, valueAccessors: Ma
9
10
  flattenData: Record<string, unknown>[];
10
11
  categories: string[];
11
12
  legendDomain: [number, number];
13
+ dataLookupRegistry: GeoDataLookupRegistry;
12
14
  };
@@ -47,17 +47,20 @@ const extractLayersData = (children, valueAccessors) => {
47
47
  let flattenData = [];
48
48
  const categoriesSet = /* @__PURE__ */ new Set();
49
49
  let legendDomain = [Infinity, -Infinity];
50
+ const dataLookupRegistry = /* @__PURE__ */ new Map();
50
51
  import_react.Children.forEach(children, (child) => {
51
52
  if ((0, import_is_component.isComponent)(child, import_BubbleLayer.BubbleLayer) || (0, import_is_component.isComponent)(child, import_DotLayer.DotLayer)) {
52
- const { data } = child.props;
53
- data.forEach((dataPoint) => {
53
+ const { data, layerId } = child.props;
54
+ const lookup = /* @__PURE__ */ new Map();
55
+ data.forEach((dataPoint, index) => {
56
+ lookup.set(index, dataPoint);
54
57
  const extendedDataPoint = {
55
58
  ...dataPoint,
56
- "layer-name": child.props.layerId
59
+ "layer-name": layerId
57
60
  };
58
61
  const category = addCategory(
59
62
  extendedDataPoint,
60
- valueAccessors.get(child.props.layerId)
63
+ valueAccessors.get(layerId)
61
64
  );
62
65
  category && categoriesSet.add(category);
63
66
  if (typeof category === "number") {
@@ -65,14 +68,14 @@ const extractLayersData = (children, valueAccessors) => {
65
68
  }
66
69
  flattenData = flattenData.concat(extendedDataPoint);
67
70
  });
71
+ dataLookupRegistry.set(`source-${layerId}`, lookup);
68
72
  } else if ((0, import_is_component.isComponent)(child, import_ConnectionLayer.ConnectionLayer)) {
69
- const { data } = child.props;
73
+ const { data, layerId } = child.props;
74
+ const lookup = /* @__PURE__ */ new Map();
70
75
  data.forEach((connection, connectionIndex) => {
76
+ lookup.set(connectionIndex, connection);
71
77
  if (connection.path.length >= 2) {
72
- const category = addCategory(
73
- connection,
74
- valueAccessors.get(child.props.layerId)
75
- );
78
+ const category = addCategory(connection, valueAccessors.get(layerId));
76
79
  category && categoriesSet.add(category);
77
80
  if (typeof category === "number") {
78
81
  legendDomain = updateDomain(legendDomain, category);
@@ -82,24 +85,28 @@ const extractLayersData = (children, valueAccessors) => {
82
85
  ...path,
83
86
  "connection-name": `connection-${connectionIndex + 1}`,
84
87
  "connection-item-index": pathIndex,
85
- "layer-name": child.props.layerId
88
+ "layer-name": layerId
86
89
  };
87
90
  flattenData.push(parsedPath);
88
91
  });
89
92
  }
90
93
  });
94
+ dataLookupRegistry.set(`source-${layerId}`, lookup);
91
95
  } else if ((0, import_is_component.isComponent)(child, import_ChoroplethLayer.ChoroplethLayer)) {
92
- const { data, regionAccessor } = child.props;
93
- data.forEach((dataEntry) => {
96
+ const { data, regionAccessor, layerId } = child.props;
97
+ const sourceId = layerId.replace("layer", "source");
98
+ const lookup = /* @__PURE__ */ new Map();
99
+ data.forEach((dataEntry, index) => {
100
+ lookup.set(index, dataEntry);
94
101
  const region = (0, import_lodash_es.isString)(regionAccessor) ? dataEntry[regionAccessor] : regionAccessor(dataEntry);
95
102
  const choroplethLayerData = {
96
103
  ...dataEntry,
97
104
  region,
98
- "layer-name": child.props.layerId
105
+ "layer-name": layerId
99
106
  };
100
107
  const category = addCategory(
101
108
  choroplethLayerData,
102
- valueAccessors.get(child.props.layerId)
109
+ valueAccessors.get(layerId)
103
110
  );
104
111
  category && categoriesSet.add(category);
105
112
  if (typeof category === "number") {
@@ -107,11 +114,13 @@ const extractLayersData = (children, valueAccessors) => {
107
114
  }
108
115
  flattenData.push(choroplethLayerData);
109
116
  });
117
+ dataLookupRegistry.set(sourceId, lookup);
110
118
  }
111
119
  });
112
120
  return {
113
121
  flattenData,
114
122
  categories: [...categoriesSet],
115
- legendDomain
123
+ legendDomain,
124
+ dataLookupRegistry
116
125
  };
117
126
  };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @returns true if is firefox browser, false otherwise
3
+ * @internal
4
+ */
5
+ export declare function isFirefox(): boolean;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var is_browser_firefox_exports = {};
20
+ __export(is_browser_firefox_exports, {
21
+ isFirefox: () => isFirefox
22
+ });
23
+ module.exports = __toCommonJS(is_browser_firefox_exports);
24
+ function isFirefox() {
25
+ return typeof navigator !== "undefined" && navigator.userAgent.toLowerCase().includes("firefox");
26
+ }
@@ -1,10 +1,18 @@
1
1
  import type { MapGeoJSONFeature, MapLayerMouseEvent } from 'maplibre-gl';
2
+ import type { GeoDataLookupRegistry } from '../contexts/geo-data-lookup.context.js';
2
3
  /**
3
- * Extracts useful map features data for the tooltip
4
+ * Extracts useful map features data for the tooltip.
5
+ *
6
+ * When a data lookup registry is provided, the full original data
7
+ * is restored from the `__dataIndex` stored in GeoJSON properties.
8
+ * This allows GeoJSON features to carry only rendering-relevant
9
+ * fields while still providing full data for tooltips.
10
+ *
4
11
  * @param features - map features
12
+ * @param registry - optional data lookup registry for restoring full data
5
13
  */
6
- export declare const parseTooltipData: (features: MapGeoJSONFeature[]) => unknown[];
7
- export declare const extractDataFromEvent: (event: MapLayerMouseEvent) => {
14
+ export declare const parseTooltipData: (features: MapGeoJSONFeature[], registry?: GeoDataLookupRegistry) => unknown[];
15
+ export declare const extractDataFromEvent: (event: MapLayerMouseEvent, registry?: GeoDataLookupRegistry) => {
8
16
  featureId?: undefined;
9
17
  hoveredLayerId?: undefined;
10
18
  data?: undefined;
@@ -40,20 +40,35 @@ const parseFeatureProperties = (featureProperties) => {
40
40
  }
41
41
  return properties;
42
42
  };
43
- const parseTooltipData = (features) => {
43
+ const resolveSourceId = (feature) => feature.source ?? feature.layer?.source;
44
+ const restoreDataFromLookup = (sourceId, dataIndex, registry) => {
45
+ if (registry === void 0 || sourceId === void 0 || dataIndex === void 0) {
46
+ return void 0;
47
+ }
48
+ const lookup = registry.get(sourceId);
49
+ return lookup?.get(dataIndex);
50
+ };
51
+ const parseTooltipData = (features, registry) => {
44
52
  const data = [];
45
53
  for (const feature of features) {
46
54
  const properties = parseFeatureProperties(feature.properties);
47
- const [latitude, longitude] = feature.geometry.coordinates;
55
+ const sourceId = resolveSourceId(feature);
56
+ const { __dataIndex, ...visibleProperties } = properties;
57
+ const dataIndex = typeof __dataIndex === "number" ? __dataIndex : void 0;
58
+ const originalData = restoreDataFromLookup(sourceId, dataIndex, registry);
59
+ const coordinates = feature.geometry.type === "Point" ? {
60
+ longitude: feature.geometry.coordinates[0],
61
+ latitude: feature.geometry.coordinates[1]
62
+ } : {};
48
63
  data.push({
49
- ...properties,
50
- latitude,
51
- longitude
64
+ ...visibleProperties,
65
+ ...originalData !== void 0 ? { data: originalData } : {},
66
+ ...coordinates
52
67
  });
53
68
  }
54
69
  return data;
55
70
  };
56
- const extractDataFromEvent = (event) => {
71
+ const extractDataFromEvent = (event, registry) => {
57
72
  if (!event.features?.length) {
58
73
  return {};
59
74
  }
@@ -62,7 +77,7 @@ const extractDataFromEvent = (event) => {
62
77
  const hoveredFeatures = event.features.filter(
63
78
  (feature2) => feature2.layer.id === hoveredLayerId
64
79
  );
65
- const data = parseTooltipData(hoveredFeatures);
80
+ const data = parseTooltipData(hoveredFeatures, registry);
66
81
  return {
67
82
  featureId: `${hoveredLayerId}-${feature.id}`,
68
83
  hoveredLayerId,