@trackunit/react-map 0.2.210-alpha-7afddbbe4cc.0 → 0.2.211
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs.js +39 -3
- package/index.esm.js +39 -3
- package/package.json +11 -11
- package/src/index.d.ts +1 -1
- package/src/layers/types.d.ts +4 -2
- package/src/layers/useHeatmap/useHeatmap.d.ts +9 -0
- package/src/layers/useHeatmap/utils/warnHeatmap.d.ts +1 -1
package/index.cjs.js
CHANGED
|
@@ -5888,10 +5888,10 @@ const useFitToContent = (api, handles, options) => {
|
|
|
5888
5888
|
};
|
|
5889
5889
|
|
|
5890
5890
|
/**
|
|
5891
|
-
* Single dev-warning channel for `useHeatmap` (invalid data, invalid style).
|
|
5891
|
+
* Single dev-warning channel for `useHeatmap` (invalid data, invalid style, unhandled render errors).
|
|
5892
5892
|
*/
|
|
5893
5893
|
const warnHeatmap = (message, ...details) => {
|
|
5894
|
-
// eslint-disable-next-line no-console -- Intentional: the one heatmap warning channel; invalid input is dropped or defaulted and must stay visible
|
|
5894
|
+
// eslint-disable-next-line no-console -- Intentional: the one heatmap warning channel; invalid input is dropped or defaulted and render errors without onError must stay visible
|
|
5895
5895
|
console.warn(`[useHeatmap] ${message}`, ...details);
|
|
5896
5896
|
};
|
|
5897
5897
|
|
|
@@ -6040,8 +6040,41 @@ const EMPTY_CONTROLS$2 = {};
|
|
|
6040
6040
|
* - Renderers: ADR-0029 (`libs/react/map/docs/adr/0029-heatmap-provider-specific-renderers.md`).
|
|
6041
6041
|
*/
|
|
6042
6042
|
const useHeatmap = (options) => {
|
|
6043
|
-
const { id, name, data, getPosition, getWeight, style, controls, loading, fitParticipation = "all" } = options;
|
|
6043
|
+
const { id, name, data, getPosition, getWeight, style, onError, controls, loading, fitParticipation = "all", } = options;
|
|
6044
6044
|
const layerReady = useLayerReady(loading);
|
|
6045
|
+
const onErrorRef = react.useRef(onError);
|
|
6046
|
+
react.useEffect(() => {
|
|
6047
|
+
onErrorRef.current = onError;
|
|
6048
|
+
}, [onError]);
|
|
6049
|
+
const errorHandler = reactCoreHooks.useErrorHandlerOrNull();
|
|
6050
|
+
// Sentry at most once per layer/code per hook mount, like the shape hooks' fill-tiling reports.
|
|
6051
|
+
const sentryReportedKeysRef = react.useRef(new Set());
|
|
6052
|
+
const captureOnce = react.useCallback((key, message, cause, fingerprintCode) => {
|
|
6053
|
+
if (errorHandler === null || sentryReportedKeysRef.current.has(key))
|
|
6054
|
+
return;
|
|
6055
|
+
sentryReportedKeysRef.current.add(key);
|
|
6056
|
+
errorHandler.captureException(new Error(message, { cause }), {
|
|
6057
|
+
level: "warning",
|
|
6058
|
+
fingerprint: ["react-map", "heatmap", fingerprintCode],
|
|
6059
|
+
});
|
|
6060
|
+
}, [errorHandler]);
|
|
6061
|
+
const reportError = react.useCallback((error) => {
|
|
6062
|
+
const payload = JSON.stringify({ layerId: error.layerId, code: error.code });
|
|
6063
|
+
captureOnce(`${error.layerId}:${error.code}`, `Heatmap failed to render: ${payload}`, error.cause, error.code);
|
|
6064
|
+
const handler = onErrorRef.current;
|
|
6065
|
+
if (handler !== undefined) {
|
|
6066
|
+
// Adapters call this mid-sync; a throwing handler must not skip the rest of the layer snapshot.
|
|
6067
|
+
try {
|
|
6068
|
+
handler(error);
|
|
6069
|
+
}
|
|
6070
|
+
catch (handlerError) {
|
|
6071
|
+
warnHeatmap(`onError for heatmap "${error.layerId}" threw.`, handlerError, error.cause);
|
|
6072
|
+
captureOnce(`${error.layerId}:on-error-threw`, `Heatmap onError threw: ${payload}`, handlerError, "on-error-threw");
|
|
6073
|
+
}
|
|
6074
|
+
return;
|
|
6075
|
+
}
|
|
6076
|
+
warnHeatmap(`Heatmap "${error.layerId}" failed to render (${error.code}).`, error.cause);
|
|
6077
|
+
}, [captureOnce]);
|
|
6045
6078
|
// Keyed on `data` (adjust-state-during-render + isEqual) so inline accessors
|
|
6046
6079
|
// don't re-normalize the whole dataset on every render. Accessor changes
|
|
6047
6080
|
// apply on the next `data` change.
|
|
@@ -6078,6 +6111,7 @@ const useHeatmap = (options) => {
|
|
|
6078
6111
|
layerType: "heatmap",
|
|
6079
6112
|
features: normalized.features,
|
|
6080
6113
|
style: resolvedStyle,
|
|
6114
|
+
onError: reportError,
|
|
6081
6115
|
pointCount: normalized.features.features.length,
|
|
6082
6116
|
totalCount: data.length,
|
|
6083
6117
|
}), [
|
|
@@ -6090,6 +6124,7 @@ const useHeatmap = (options) => {
|
|
|
6090
6124
|
fitParticipation,
|
|
6091
6125
|
normalized.features,
|
|
6092
6126
|
resolvedStyle,
|
|
6127
|
+
reportError,
|
|
6093
6128
|
data.length,
|
|
6094
6129
|
]);
|
|
6095
6130
|
};
|
|
@@ -8482,6 +8517,7 @@ function toMapLayer(handle) {
|
|
|
8482
8517
|
id: handle.id,
|
|
8483
8518
|
features: handle.features,
|
|
8484
8519
|
style: handle.style,
|
|
8520
|
+
onError: handle.onError,
|
|
8485
8521
|
};
|
|
8486
8522
|
default: {
|
|
8487
8523
|
const exhaustiveCheck = handle;
|
package/index.esm.js
CHANGED
|
@@ -5887,10 +5887,10 @@ const useFitToContent = (api, handles, options) => {
|
|
|
5887
5887
|
};
|
|
5888
5888
|
|
|
5889
5889
|
/**
|
|
5890
|
-
* Single dev-warning channel for `useHeatmap` (invalid data, invalid style).
|
|
5890
|
+
* Single dev-warning channel for `useHeatmap` (invalid data, invalid style, unhandled render errors).
|
|
5891
5891
|
*/
|
|
5892
5892
|
const warnHeatmap = (message, ...details) => {
|
|
5893
|
-
// eslint-disable-next-line no-console -- Intentional: the one heatmap warning channel; invalid input is dropped or defaulted and must stay visible
|
|
5893
|
+
// eslint-disable-next-line no-console -- Intentional: the one heatmap warning channel; invalid input is dropped or defaulted and render errors without onError must stay visible
|
|
5894
5894
|
console.warn(`[useHeatmap] ${message}`, ...details);
|
|
5895
5895
|
};
|
|
5896
5896
|
|
|
@@ -6039,8 +6039,41 @@ const EMPTY_CONTROLS$2 = {};
|
|
|
6039
6039
|
* - Renderers: ADR-0029 (`libs/react/map/docs/adr/0029-heatmap-provider-specific-renderers.md`).
|
|
6040
6040
|
*/
|
|
6041
6041
|
const useHeatmap = (options) => {
|
|
6042
|
-
const { id, name, data, getPosition, getWeight, style, controls, loading, fitParticipation = "all" } = options;
|
|
6042
|
+
const { id, name, data, getPosition, getWeight, style, onError, controls, loading, fitParticipation = "all", } = options;
|
|
6043
6043
|
const layerReady = useLayerReady(loading);
|
|
6044
|
+
const onErrorRef = useRef(onError);
|
|
6045
|
+
useEffect(() => {
|
|
6046
|
+
onErrorRef.current = onError;
|
|
6047
|
+
}, [onError]);
|
|
6048
|
+
const errorHandler = useErrorHandlerOrNull();
|
|
6049
|
+
// Sentry at most once per layer/code per hook mount, like the shape hooks' fill-tiling reports.
|
|
6050
|
+
const sentryReportedKeysRef = useRef(new Set());
|
|
6051
|
+
const captureOnce = useCallback((key, message, cause, fingerprintCode) => {
|
|
6052
|
+
if (errorHandler === null || sentryReportedKeysRef.current.has(key))
|
|
6053
|
+
return;
|
|
6054
|
+
sentryReportedKeysRef.current.add(key);
|
|
6055
|
+
errorHandler.captureException(new Error(message, { cause }), {
|
|
6056
|
+
level: "warning",
|
|
6057
|
+
fingerprint: ["react-map", "heatmap", fingerprintCode],
|
|
6058
|
+
});
|
|
6059
|
+
}, [errorHandler]);
|
|
6060
|
+
const reportError = useCallback((error) => {
|
|
6061
|
+
const payload = JSON.stringify({ layerId: error.layerId, code: error.code });
|
|
6062
|
+
captureOnce(`${error.layerId}:${error.code}`, `Heatmap failed to render: ${payload}`, error.cause, error.code);
|
|
6063
|
+
const handler = onErrorRef.current;
|
|
6064
|
+
if (handler !== undefined) {
|
|
6065
|
+
// Adapters call this mid-sync; a throwing handler must not skip the rest of the layer snapshot.
|
|
6066
|
+
try {
|
|
6067
|
+
handler(error);
|
|
6068
|
+
}
|
|
6069
|
+
catch (handlerError) {
|
|
6070
|
+
warnHeatmap(`onError for heatmap "${error.layerId}" threw.`, handlerError, error.cause);
|
|
6071
|
+
captureOnce(`${error.layerId}:on-error-threw`, `Heatmap onError threw: ${payload}`, handlerError, "on-error-threw");
|
|
6072
|
+
}
|
|
6073
|
+
return;
|
|
6074
|
+
}
|
|
6075
|
+
warnHeatmap(`Heatmap "${error.layerId}" failed to render (${error.code}).`, error.cause);
|
|
6076
|
+
}, [captureOnce]);
|
|
6044
6077
|
// Keyed on `data` (adjust-state-during-render + isEqual) so inline accessors
|
|
6045
6078
|
// don't re-normalize the whole dataset on every render. Accessor changes
|
|
6046
6079
|
// apply on the next `data` change.
|
|
@@ -6077,6 +6110,7 @@ const useHeatmap = (options) => {
|
|
|
6077
6110
|
layerType: "heatmap",
|
|
6078
6111
|
features: normalized.features,
|
|
6079
6112
|
style: resolvedStyle,
|
|
6113
|
+
onError: reportError,
|
|
6080
6114
|
pointCount: normalized.features.features.length,
|
|
6081
6115
|
totalCount: data.length,
|
|
6082
6116
|
}), [
|
|
@@ -6089,6 +6123,7 @@ const useHeatmap = (options) => {
|
|
|
6089
6123
|
fitParticipation,
|
|
6090
6124
|
normalized.features,
|
|
6091
6125
|
resolvedStyle,
|
|
6126
|
+
reportError,
|
|
6092
6127
|
data.length,
|
|
6093
6128
|
]);
|
|
6094
6129
|
};
|
|
@@ -8481,6 +8516,7 @@ function toMapLayer(handle) {
|
|
|
8481
8516
|
id: handle.id,
|
|
8482
8517
|
features: handle.features,
|
|
8483
8518
|
style: handle.style,
|
|
8519
|
+
onError: handle.onError,
|
|
8484
8520
|
};
|
|
8485
8521
|
default: {
|
|
8486
8522
|
const exhaustiveCheck = handle;
|
package/package.json
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-map",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.211",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=24.x"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@trackunit/react-components": "3.8.4
|
|
11
|
-
"@trackunit/css-class-variance-utilities": "2.3.
|
|
12
|
-
"@trackunit/react-form-components": "2.10.11
|
|
13
|
-
"@trackunit/react-core-hooks": "1.25.
|
|
14
|
-
"@trackunit/geo-json-utils": "1.18.
|
|
15
|
-
"@trackunit/i18n-library-translation": "2.8.
|
|
10
|
+
"@trackunit/react-components": "3.8.4",
|
|
11
|
+
"@trackunit/css-class-variance-utilities": "2.3.6",
|
|
12
|
+
"@trackunit/react-form-components": "2.10.11",
|
|
13
|
+
"@trackunit/react-core-hooks": "1.25.6",
|
|
14
|
+
"@trackunit/geo-json-utils": "1.18.6",
|
|
15
|
+
"@trackunit/i18n-library-translation": "2.8.6",
|
|
16
16
|
"react-minimal-pie-chart": "^8.4.0",
|
|
17
|
-
"@trackunit/react-map-adapter-shared": "0.0.158
|
|
18
|
-
"@trackunit/react-map-color-utils": "0.0.
|
|
19
|
-
"@trackunit/shared-utils": "1.19.
|
|
20
|
-
"@trackunit/ui-design-tokens": "1.18.
|
|
17
|
+
"@trackunit/react-map-adapter-shared": "0.0.158",
|
|
18
|
+
"@trackunit/react-map-color-utils": "0.0.132",
|
|
19
|
+
"@trackunit/shared-utils": "1.19.6",
|
|
20
|
+
"@trackunit/ui-design-tokens": "1.18.6",
|
|
21
21
|
"@floating-ui/react": "^0.26.25",
|
|
22
22
|
"es-toolkit": "^1.52.0",
|
|
23
23
|
"tailwind-merge": "^2.0.0",
|
package/src/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export type { ControlMiddleware, MiddlewareContext } from "./controls/renderingR
|
|
|
24
24
|
export type { CategoryMetadata } from "./controls/collapseControls";
|
|
25
25
|
export type { ClusterEntity, Entity, MapInteractionState, MarkerEntity, RouteEntity, ShapeEntity, ShapeType, } from "@trackunit/react-map-adapter-shared";
|
|
26
26
|
export { geometryTypeToShapeType, INITIAL_INTERACTION_STATE } from "@trackunit/react-map-adapter-shared";
|
|
27
|
-
export type { AdaptiveMarkerResolution, AdaptiveRenderConfig, AdaptiveRenderState, AdaptiveResolutionContext, CircleSymbolDescriptor, ClientClusterConfig, ClusterConfig, ClusterInfo, ClusterRenderState, ClusterSymbolStyle, CommonRenderState, DomPortalStackingInput, DomPortalStackingResolver, DomPortalStackingResult, DomRenderConfig, DomRenderState, FitParticipation, GeoJsonFeature, GeoJsonFeatureCollection, GeoJsonGeometry, HeatmapLayerHandle, HeatmapRgbaColor, ImageOverlayHandle, LayerHandle, LayerMeta, MarkerAnchor, MarkerDomPortalStackGeometry, MarkerDomPortalStackPhase, MarkerLayerHandle, RenderConfig, RenderMedium, ResolutionContext, RouteLayerHandle, RouteStyle, ServerClusterConfig, ShapeInteractiveMode, ShapeLayerHandle, ShapeOverlapConfig, ShapeStyle, ShapeStyleOverrides, ShapesUnderCursorHit, SymbolDescriptor, SymbolRenderConfig, SymbolRenderState, } from "./layers/types";
|
|
27
|
+
export type { AdaptiveMarkerResolution, AdaptiveRenderConfig, AdaptiveRenderState, AdaptiveResolutionContext, CircleSymbolDescriptor, ClientClusterConfig, ClusterConfig, ClusterInfo, ClusterRenderState, ClusterSymbolStyle, CommonRenderState, DomPortalStackingInput, DomPortalStackingResolver, DomPortalStackingResult, DomRenderConfig, DomRenderState, FitParticipation, GeoJsonFeature, GeoJsonFeatureCollection, GeoJsonGeometry, HeatmapLayerHandle, HeatmapRenderError, HeatmapRgbaColor, ImageOverlayHandle, LayerHandle, LayerMeta, MarkerAnchor, MarkerDomPortalStackGeometry, MarkerDomPortalStackPhase, MarkerLayerHandle, RenderConfig, RenderMedium, ResolutionContext, RouteLayerHandle, RouteStyle, ServerClusterConfig, ShapeInteractiveMode, ShapeLayerHandle, ShapeOverlapConfig, ShapeStyle, ShapeStyleOverrides, ShapesUnderCursorHit, SymbolDescriptor, SymbolRenderConfig, SymbolRenderState, } from "./layers/types";
|
|
28
28
|
export { computeMarkerDomPortalZIndex } from "./layers/types";
|
|
29
29
|
export { ANCHOR_SELECTOR, HIT_SURFACE_SELECTOR } from "@trackunit/react-map-adapter-shared";
|
|
30
30
|
export { ClusterMarker, type ClusterMarkerProps, type ClusterMarkerStickInput, type ClusterSegment, } from "./clusters/ClusterMarker";
|
package/src/layers/types.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { GeoJsonBbox, GeoJsonFeature, GeoJsonFeatureCollection, GeoJsonGeometry, GeoJsonPosition } from "@trackunit/geo-json-utils";
|
|
2
|
-
import type { AdaptiveMarkerResolution, ClusterConfig, ClusterRenderConfig, HeatmapRenderStyle, RenderConfig, RouteStyle, ShapeInteractiveMode, ShapeStyle } from "@trackunit/react-map-adapter-shared";
|
|
2
|
+
import type { AdaptiveMarkerResolution, ClusterConfig, ClusterRenderConfig, HeatmapRenderError, HeatmapRenderStyle, RenderConfig, RouteStyle, ShapeInteractiveMode, ShapeStyle } from "@trackunit/react-map-adapter-shared";
|
|
3
3
|
import type { CategoryKey, ControlConfig } from "../controls/types";
|
|
4
4
|
import type { ShapeDecoration } from "./useShapes/shapeDecorations";
|
|
5
5
|
import type { ShapesUnderCursorHit } from "./useShapes/shapeFillTiling";
|
|
6
6
|
import type { ShapeLabelResolutionContext } from "./useShapes/shapeLabelResolution";
|
|
7
7
|
import type { ResolveShapeStackOrder } from "./useShapes/shapeStackOrder";
|
|
8
8
|
export type { ShapesUnderCursorHit };
|
|
9
|
-
export type { AdaptiveMarkerResolution, AdaptiveRenderConfig, AdaptiveRenderState, AdaptiveResolutionContext, CircleSymbolDescriptor, ClientClusterConfig, ClusterConfig, ClusterDomRenderConfig, ClusterInfo, ClusterRenderConfig, ClusterRenderState, ClusterSymbolRenderConfig, ClusterSymbolStyle, CommonRenderState, DomPortalStackingInput, DomPortalStackingResolver, DomPortalStackingResult, DomRenderConfig, DomRenderState, GeoJsonFeature, GeoJsonFeatureCollection, GeoJsonGeometry, HeatmapRenderStyle, HeatmapRgbaColor, MarkerAnchor, MarkerDomPortalStackGeometry, MarkerDomPortalStackPhase, PixelOffset, RenderConfig, RenderMedium, ResolutionContext, RouteStyle, ServerClusterConfig, ShapeInteractiveMode, ShapeStyle, ShapeStyleOverrides, SymbolDescriptor, SymbolRenderConfig, SymbolRenderState, } from "@trackunit/react-map-adapter-shared";
|
|
9
|
+
export type { AdaptiveMarkerResolution, AdaptiveRenderConfig, AdaptiveRenderState, AdaptiveResolutionContext, CircleSymbolDescriptor, ClientClusterConfig, ClusterConfig, ClusterDomRenderConfig, ClusterInfo, ClusterRenderConfig, ClusterRenderState, ClusterSymbolRenderConfig, ClusterSymbolStyle, CommonRenderState, DomPortalStackingInput, DomPortalStackingResolver, DomPortalStackingResult, DomRenderConfig, DomRenderState, GeoJsonFeature, GeoJsonFeatureCollection, GeoJsonGeometry, HeatmapRenderError, HeatmapRenderStyle, HeatmapRgbaColor, MarkerAnchor, MarkerDomPortalStackGeometry, MarkerDomPortalStackPhase, PixelOffset, RenderConfig, RenderMedium, ResolutionContext, RouteStyle, ServerClusterConfig, ShapeInteractiveMode, ShapeStyle, ShapeStyleOverrides, SymbolDescriptor, SymbolRenderConfig, SymbolRenderState, } from "@trackunit/react-map-adapter-shared";
|
|
10
10
|
export { computeMarkerDomPortalZIndex } from "@trackunit/react-map-adapter-shared";
|
|
11
11
|
/**
|
|
12
12
|
* Controls whether a layer's bounds are included in fit-to-content operations.
|
|
@@ -191,6 +191,8 @@ export interface HeatmapLayerHandle extends LayerMeta {
|
|
|
191
191
|
readonly layerType: "heatmap";
|
|
192
192
|
readonly features: GeoJsonFeatureCollection;
|
|
193
193
|
readonly style: HeatmapRenderStyle;
|
|
194
|
+
/** Stable error reporter forwarded to the adapter; calls the consumer's latest `onError` or warns. */
|
|
195
|
+
readonly onError: (error: HeatmapRenderError) => void;
|
|
194
196
|
}
|
|
195
197
|
/**
|
|
196
198
|
* Discriminated union of all layer handle types.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { GeoJsonPosition } from "@trackunit/geo-json-utils";
|
|
2
|
+
import type { HeatmapRenderError } from "@trackunit/react-map-adapter-shared";
|
|
2
3
|
import type { CategoryKey, ControlConfig } from "../../controls/types";
|
|
3
4
|
import type { FitParticipation, HeatmapLayerHandle } from "../types";
|
|
4
5
|
export type HeatmapStyle = Readonly<{
|
|
@@ -21,6 +22,14 @@ export type UseHeatmapOptions<TItem> = Readonly<{
|
|
|
21
22
|
getPosition: (item: TItem) => GeoJsonPosition | null;
|
|
22
23
|
getWeight?: (item: TItem) => number;
|
|
23
24
|
style?: HeatmapStyle;
|
|
25
|
+
/**
|
|
26
|
+
* Called once per failed renderer load or update (for example when the Google deck.gl chunk fails to load).
|
|
27
|
+
* The basemap and other layers keep rendering. Without it, failures are logged with `console.warn`.
|
|
28
|
+
* Failures are reported to the app's error handler (Sentry) either way.
|
|
29
|
+
* After a renderer failure (for example WebGL context loss on Google), the heatmap stays hidden until the next map
|
|
30
|
+
* layer or interaction change triggers a retry; nothing retries on an idle map.
|
|
31
|
+
*/
|
|
32
|
+
onError?: (error: HeatmapRenderError) => void;
|
|
24
33
|
controls?: Partial<Record<CategoryKey, ReadonlyArray<ControlConfig>>>;
|
|
25
34
|
loading?: boolean;
|
|
26
35
|
fitParticipation?: FitParticipation;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Single dev-warning channel for `useHeatmap` (invalid data, invalid style).
|
|
2
|
+
* Single dev-warning channel for `useHeatmap` (invalid data, invalid style, unhandled render errors).
|
|
3
3
|
*/
|
|
4
4
|
export declare const warnHeatmap: (message: string, ...details: ReadonlyArray<unknown>) => void;
|