@tileflow/react 0.1.0-alpha.37 → 0.1.0-alpha.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -109,7 +109,7 @@ Add `timeOfDay="dusk"` beside `theme` to select a map's optional `day`, `dawn`,
109
109
  `night` preset. For Streets, `theme="light"` with this preset selects the existing `dusk` palette.
110
110
  Maps without this capability ignore the option; omitting it keeps the selected theme unchanged.
111
111
  Changing it uses the existing theme transition. `themeBlend` takes precedence. See the
112
- [authoring contract](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/README.md#style-with-themes-and-semantic-modules).
112
+ [authoring contract](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/REFERENCE.md#style-with-themes-and-semantic-modules).
113
113
 
114
114
  Theme and `timeOfDay` changes cross-fade over 450 ms by default, respecting reduced motion.
115
115
  `themeTransition={{duration: 700}}` customizes the duration; use `duration: 0` for an immediate change.
@@ -245,6 +245,26 @@ annotation-only. See the
245
245
  Text/field content uses safe text defaults. A `view` is an application renderer name, not HTML.
246
246
  Keep tooltips non-interactive; put buttons, links, and forms in popups.
247
247
 
248
+ ## Cluster points and draw density
249
+
250
+ Use `annotationClusters` for up to 1,000 annotations, or `dataSources` and `dataOverlays` for larger
251
+ GeoJSON sets. Clicking a cluster zooms in and reports a `cluster` target through `onInteractionEvent`.
252
+
253
+ <!-- docs:check -->
254
+
255
+ ```ts
256
+ import {clusterOverlay, geojsonSource} from '@tileflow/core/runtime';
257
+
258
+ export const dataSources = {stores: geojsonSource({cluster: true, clusterRadius: 50})};
259
+ export const dataOverlays = {
260
+ stores: clusterOverlay({id: 'stores', placement: 'above-labels', source: 'stores'}),
261
+ };
262
+ ```
263
+
264
+ See the
265
+ [interactions reference](https://github.com/tileflow/tileflow-sdk/blob/main/packages/interactions/REFERENCE.md)
266
+ for heatmaps, events, and polygon drawing with Terra Draw.
267
+
248
268
  ## Display an image or create a render
249
269
 
250
270
  `<Map mode="image">` displays an explicit `imageUrl` or derives an image URL from the selected
package/dist/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { Map as Map$1, MapOptions } from 'maplibre-gl';
2
- import { TileflowBoundaryValues } from '@tileflow/core';
2
+ import { TileflowBoundaryValues, TileflowMapLibreOverlay, TileflowGeoJsonSource } from '@tileflow/core';
3
3
  import { CreateBoundaryFeatureStateOptions, TileflowBrowserThemeBlendSelection, TileflowThemeTransitionOptions, TileflowViewMode, TileflowThemeTransition } from '@tileflow/core/browser';
4
4
  import * as react from 'react';
5
5
  import { CSSProperties, ImgHTMLAttributes, ReactNode } from 'react';
6
6
  import { TileflowRuntimeSource, TileflowThemeSelection, TileflowTimeOfDay, TileflowAnalytics } from '@tileflow/core/runtime';
7
7
  import { TileflowAnnotation, TileflowInteractionState, TileflowAnnotationViewContext, TileflowInteractionBinding, TileflowInteractionViewContext, TileflowInteractionDiagnostic, TileflowInteractionEvent } from '@tileflow/interactions';
8
+ import { TileflowAnnotationClusterOptions } from '@tileflow/interactions/maplibre';
8
9
 
9
10
  /**
10
11
  * Keep a map's Boundaries feature-state equal to `values`. Pass the map from `<Map onLoad>` and
@@ -65,7 +66,13 @@ type TileflowInteractionRendererProps<TAnnotation extends TileflowAnnotation> =
65
66
  renderTooltip?: TileflowInteractionRenderer<TAnnotation>;
66
67
  }>;
67
68
  type MapInteractiveProps<TAnnotation extends TileflowAnnotation> = MapSharedProps & TileflowInteractionStateInputProps & TileflowInteractionRendererProps<TAnnotation> & {
69
+ /** Group `annotations` into accessible cluster buttons. Up to 1,000 annotations. */
70
+ annotationClusters?: TileflowAnnotationClusterOptions;
68
71
  annotations?: readonly TAnnotation[];
72
+ /** Overlays drawn over `dataSources` or compiled sources, keyed as in `defineMap`. */
73
+ dataOverlays?: Readonly<Record<string, TileflowMapLibreOverlay>>;
74
+ /** Application GeoJSON, keyed as in `defineMap`. A compiled source of the same key is filled. */
75
+ dataSources?: Readonly<Record<string, TileflowGeoJsonSource>>;
69
76
  mode?: 'interactive';
70
77
  onInteractionDiagnostic?: (diagnostic: TileflowInteractionDiagnostic) => void;
71
78
  onInteractionEvent?: (event: TileflowInteractionEvent<TAnnotation>) => void;
@@ -73,7 +80,10 @@ type MapInteractiveProps<TAnnotation extends TileflowAnnotation> = MapSharedProp
73
80
  renderMarker?: TileflowAnnotationRenderer<TAnnotation>;
74
81
  };
75
82
  type MapImageProps = MapSharedProps & {
83
+ annotationClusters?: never;
76
84
  annotations?: never;
85
+ dataOverlays?: never;
86
+ dataSources?: never;
77
87
  defaultInteractionState?: never;
78
88
  interactionState?: never;
79
89
  interactions?: never;
package/dist/index.js CHANGED
@@ -80,6 +80,7 @@ import {
80
80
  resolveTileflowStaticImageUrl
81
81
  } from "@tileflow/core/runtime";
82
82
  import {
83
+ createTileflowMapLibreDataRuntime,
83
84
  createTileflowMapLibreDomRuntime,
84
85
  createTileflowMapLibreInteractionCoordinator,
85
86
  createTileflowMapLibreSemanticDomRuntime
@@ -285,7 +286,10 @@ var defaultInteractions = [];
285
286
  function Map2(props) {
286
287
  assertTileflowMapStyleInputs(props);
287
288
  const {
289
+ annotationClusters,
288
290
  annotations,
291
+ dataOverlays,
292
+ dataSources,
289
293
  captureId,
290
294
  defaultInteractionState,
291
295
  mode = "interactive",
@@ -362,6 +366,8 @@ function Map2(props) {
362
366
  const interactionCoordinatorRef = useRef(
363
367
  void 0
364
368
  );
369
+ const dataRuntimeRef = useRef(void 0);
370
+ const dataInputRef = useRef({});
365
371
  const annotationsRef = useRef(preparedAnnotations.annotations);
366
372
  const annotationTitlesRef = useRef(preparedAnnotations.titles);
367
373
  const preparedInteractionsRef = useRef(preparedInteractions);
@@ -456,7 +462,7 @@ function Map2(props) {
456
462
  const mapNameRef = useRef(mapName);
457
463
  const resolvedAnalyticsRef = useRef(void 0);
458
464
  const readinessRunRef = useRef(0);
459
- const hasAdditionalInteractionConfiguration = annotations !== void 0 || defaultInteractionState !== void 0 || interactionState !== void 0 || onInteractionDiagnostic !== void 0 || onInteractionEvent !== void 0 || onInteractionStateChange !== void 0 || renderMarker !== void 0 || renderPopup !== void 0 || renderTooltip !== void 0 || props.interactions !== void 0;
465
+ const hasAdditionalInteractionConfiguration = annotationClusters !== void 0 || annotations !== void 0 || dataOverlays !== void 0 || dataSources !== void 0 || defaultInteractionState !== void 0 || interactionState !== void 0 || onInteractionDiagnostic !== void 0 || onInteractionEvent !== void 0 || onInteractionStateChange !== void 0 || renderMarker !== void 0 || renderPopup !== void 0 || renderTooltip !== void 0 || props.interactions !== void 0;
460
466
  const modeDiagnostic = useMemo(
461
467
  () => isImageMode ? imageModeMapInteractionDiagnostic(
462
468
  preparedAnnotations.annotations.length,
@@ -683,6 +689,15 @@ function Map2(props) {
683
689
  onInteractionDiagnosticRef.current?.(diagnostic);
684
690
  }
685
691
  }, [preparedAnnotations]);
692
+ dataInputRef.current = {
693
+ annotationClusters,
694
+ annotations: preparedAnnotations.annotations,
695
+ dataOverlays,
696
+ dataSources
697
+ };
698
+ useEffect2(() => {
699
+ dataRuntimeRef.current?.reconcile(dataInputRef.current);
700
+ }, [annotationClusters, dataOverlays, dataSources, preparedAnnotations]);
686
701
  useEffect2(() => {
687
702
  const runtime = semanticRuntimeRef.current;
688
703
  if (!runtime || !preparedInteractions.ok) return;
@@ -951,6 +966,23 @@ function Map2(props) {
951
966
  interactionRuntimeRef.current = interactionRuntime;
952
967
  setupResources.annotationRuntime = interactionRuntime;
953
968
  registerCleanup(() => interactionRuntime.dispose());
969
+ const dataRuntime = createTileflowMapLibreDataRuntime({
970
+ createMarker: ({ element }) => wrapMapLibrePositioned(new maplibregl.Marker({ element })),
971
+ document: container.ownerDocument,
972
+ map,
973
+ onDiagnostic(diagnostic) {
974
+ onInteractionDiagnosticRef.current?.(diagnostic);
975
+ },
976
+ onInteractionEvent(event) {
977
+ onInteractionEventRef.current?.(event);
978
+ },
979
+ setHiddenAnnotations: interactionRuntime.setHiddenAnnotations
980
+ });
981
+ dataRuntimeRef.current = dataRuntime;
982
+ registerCleanup(() => {
983
+ dataRuntime.dispose();
984
+ if (dataRuntimeRef.current === dataRuntime) dataRuntimeRef.current = void 0;
985
+ });
954
986
  const semanticRuntime = createTileflowMapLibreSemanticDomRuntime({
955
987
  cancelFrame: (frame) => browserWindow.cancelAnimationFrame(frame),
956
988
  createOverlay({ container: overlayContainer, kind }) {
@@ -1029,6 +1061,7 @@ function Map2(props) {
1029
1061
  setAnnotationBridgeDiagnostic(diagnostic);
1030
1062
  onInteractionDiagnosticRef.current?.(diagnostic);
1031
1063
  }
1064
+ dataRuntime.reconcile(dataInputRef.current);
1032
1065
  const initialInteractions = preparedInteractionsRef.current;
1033
1066
  if (initialInteractions.ok) {
1034
1067
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tileflow/react",
3
- "version": "0.1.0-alpha.37",
3
+ "version": "0.1.0-alpha.38",
4
4
  "license": "Apache-2.0",
5
5
  "description": "React components for rendering Tileflow maps with MapLibre.",
6
6
  "type": "module",
@@ -43,9 +43,9 @@
43
43
  "access": "public"
44
44
  },
45
45
  "dependencies": {
46
- "@tileflow/core": ">=0.1.0-alpha.45 <0.1.0-beta.0",
47
- "@tileflow/interactions": ">=0.1.0-alpha.7 <0.1.0-beta.0",
48
- "@tileflow/static": ">=0.1.0-alpha.29 <0.1.0-beta.0"
46
+ "@tileflow/core": ">=0.1.0-alpha.48 <0.1.0-beta.0",
47
+ "@tileflow/interactions": ">=0.1.0-alpha.8 <0.1.0-beta.0",
48
+ "@tileflow/static": ">=0.1.0-alpha.30 <0.1.0-beta.0"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "maplibre-gl": ">=6.4.1 <7",