@osm-editor-kit/street-imagery-react 0.1.0-alpha.7 → 0.1.0-alpha.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.
package/dist/index.js CHANGED
@@ -1,9 +1,7 @@
1
- import { useStreetImageryI18n } from './chunk-EE7V3OIZ.js';
2
- export { STREET_IMAGERY_MESSAGES, StreetImageryLocaleProvider, useStreetImageryI18n } from './chunk-EE7V3OIZ.js';
3
- export { MapillaryPanel, mapillaryViewFor, setMapillaryViewerOutlines, turnMapillaryViewerTo } from './chunk-53RA4OSJ.js';
4
- export { PanoramaxPanel } from './chunk-EQ2JKLGT.js';
1
+ import { useStreetImageryI18n } from './chunk-6EMFFIL2.js';
2
+ export { STREET_IMAGERY_MESSAGES, StreetImageryLocaleProvider, useStreetImageryI18n } from './chunk-6EMFFIL2.js';
5
3
  export { useViewerActions, useViewerBearing, useViewerHfov, useViewerLngLat } from './chunk-25UGGXIE.js';
6
- import { distanceMeters, sequencesToFeatureCollection, emptyLineCollection, adapterById, providerById, providerCoversBbox, viewConeGeoJson, viewShapeRadiusMeters, setStreetImageryConfig, viewfieldLayerId, photoLayerId, featureLayerId, PROVIDER_IDS, mapFeatureMatchesDateRange, isBrowserAvailableProvider, photoMatchesFilters, resolvePhotoPanoramaUrl, photoFullUrlQueryKey, resolvePhotoThumbnailUrl, photoThumbnailQueryKey, formatLocalDateTime, formatMonth, formatRelativeDate, formatDateTooltip, mapillaryPhotoSource, buildViewSuggestions, yearsToMs, SIGN_TARGET, fetchMapFeatureImages, fetchMapillaryMapFeaturesInBbox, bboxAround, fetchImageDetections, findLocationOpener, mapillaryValueName, mapillaryIconUrl, openLocationInNewTab, alignLineToPoints, coneRadiusMeters, mapFeaturesToFeatureCollection, emptyPointCollection, buildMapFeatureLayerFilter, featureSourceId, photosToFeatureCollection, photosToViewfieldsFeatureCollection, emptyPolygonCollection, buildPhotoLayerFilter, photoSourceId, viewfieldSourceId, sequenceSourceId, sequenceLayerId, viewfieldLineLayerId, VIEWFIELD_MIN_ZOOM } from '@osm-editor-kit/street-imagery';
4
+ import { distanceMeters, sequencesToFeatureCollection, emptyLineCollection, adapterById, providerById, providerCoversBbox, fetchedSequencesMinZoom, viewConeGeoJson, viewShapeRadiusMeters, setStreetImageryConfig, viewfieldLayerId, photoLayerId, photoTargetLayerId, featureLayerId, PROVIDER_IDS, mapFeatureMatchesDateRange, isBrowserAvailableProvider, photoMatchesFilters, resolvePhotoPanoramaUrl, photoFullUrlQueryKey, resolvePhotoThumbnailUrl, photoThumbnailQueryKey, formatLocalDateTime, formatMonth, formatRelativeDate, formatDateTooltip, mapillaryPhotoSource, buildViewSuggestions, yearsToMs, SIGN_TARGET, fetchMapFeatureImages, fetchMapillaryMapFeaturesInBbox, bboxAround, fetchImageDetections, bestTargetImage, findLocationOpener, MAP_FEATURE_COLOR, mapillaryValueName, mapillaryIconUrl, dateRangeToSliderPositions, sliderPositionsToDateRange, dateSliderBins, dateSliderPosition, yearsAgoMs, parseIsoDateStartMs, openLocationInNewTab, formatDate, isIsoDate, alignLineToPoints, coneRadiusMeters, mapFeaturesToFeatureCollection, emptyPointCollection, buildMapFeatureLayerFilter, featureSourceId, photosToFeatureCollection, photosToViewfieldsFeatureCollection, emptyPolygonCollection, buildPhotoLayerFilter, photoSourceId, viewfieldSourceId, sequenceTilesSourceId, renameExpressionProperties, sequenceTilesLayerId, sequenceSourceId, sequenceLayerId, viewfieldLineLayerId, VIEWFIELD_MIN_ZOOM } from '@osm-editor-kit/street-imagery';
7
5
  import { Source, Layer, useMap } from 'react-map-gl/maplibre';
8
6
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
9
7
  import { lazy, useEffect, Fragment as Fragment$1, Suspense, useState, useRef, useEffectEvent } from 'react';
@@ -21,7 +19,8 @@ var StreetLevelImagerySelectionOverlay = ({
21
19
  selectedPhoto,
22
20
  selectedSequence,
23
21
  cameraLngLat,
24
- sequenceBeforeId
22
+ sequenceBeforeId,
23
+ beforeId
25
24
  }) => {
26
25
  const photoLngLat = selectedPhoto?.lngLat;
27
26
  const cameraDiffers = photoLngLat != null && cameraLngLat != null && distanceMeters(photoLngLat, cameraLngLat) > SAME_POSITION_METERS;
@@ -73,7 +72,7 @@ var StreetLevelImagerySelectionOverlay = ({
73
72
  /* @__PURE__ */ jsx(
74
73
  Layer,
75
74
  {
76
- beforeId: sequenceBeforeId,
75
+ beforeId: sequenceBeforeId ?? beforeId,
77
76
  id: "sequence-highlight-layer",
78
77
  type: "line",
79
78
  source: SEQUENCE_HIGHLIGHT_SOURCE_ID,
@@ -85,6 +84,7 @@ var StreetLevelImagerySelectionOverlay = ({
85
84
  /* @__PURE__ */ jsx(
86
85
  Layer,
87
86
  {
87
+ beforeId,
88
88
  id: "selection-connector-layer",
89
89
  type: "line",
90
90
  source: CONNECTOR_SOURCE_ID,
@@ -95,6 +95,7 @@ var StreetLevelImagerySelectionOverlay = ({
95
95
  /* @__PURE__ */ jsx(
96
96
  Layer,
97
97
  {
98
+ beforeId,
98
99
  id: "selection-highlight-layer",
99
100
  type: "circle",
100
101
  source: POINTS_SOURCE_ID,
@@ -110,6 +111,7 @@ var StreetLevelImagerySelectionOverlay = ({
110
111
  /* @__PURE__ */ jsx(
111
112
  Layer,
112
113
  {
114
+ beforeId,
113
115
  id: "selection-camera-layer",
114
116
  type: "circle",
115
117
  source: POINTS_SOURCE_ID,
@@ -137,10 +139,10 @@ var withinBbox = (bbox) => (item) => {
137
139
  const [lng, lat] = item.lngLat;
138
140
  return lng >= bbox[0] && lng <= bbox[2] && lat >= bbox[1] && lat <= bbox[3];
139
141
  };
140
- var useProviderPhotos = (providerId, bbox, zoom) => {
142
+ var useProviderPhotos = (providerId, bbox, zoom, { minZoom = 0 } = {}) => {
141
143
  const adapter = adapterById[providerId];
142
144
  const meta = providerById[providerId];
143
- const enabled = meta.kind === "photo" && bbox != null && providerCoversBbox(providerId, bbox) && zoom >= meta.minZoom && adapter?.fetchPhotos != null;
145
+ const enabled = meta.kind === "photo" && bbox != null && providerCoversBbox(providerId, bbox) && zoom >= Math.max(meta.minZoom, minZoom) && adapter?.fetchPhotos != null;
144
146
  return useQuery({
145
147
  queryKey: ["provider-photos", providerId, bboxKey(bbox), zoom],
146
148
  queryFn: async ({ signal }) => {
@@ -151,11 +153,11 @@ var useProviderPhotos = (providerId, bbox, zoom) => {
151
153
  placeholderData: (previous) => previous
152
154
  });
153
155
  };
154
- var useProviderSequences = (providerId, bbox, zoom) => {
156
+ var useProviderSequences = (providerId, bbox, zoom, { minZoom = 0 } = {}) => {
155
157
  const adapter = adapterById[providerId];
156
158
  const meta = providerById[providerId];
157
- const sequencesMinZoom = meta.sequencesMinZoom;
158
- const enabled = meta.kind === "photo" && bbox != null && providerCoversBbox(providerId, bbox) && zoom >= sequencesMinZoom && adapter?.fetchSequences != null;
159
+ const sequencesMinZoom = fetchedSequencesMinZoom(providerId);
160
+ const enabled = meta.kind === "photo" && bbox != null && providerCoversBbox(providerId, bbox) && zoom >= Math.max(sequencesMinZoom, minZoom) && adapter?.fetchSequences != null;
159
161
  return useQuery({
160
162
  queryKey: ["provider-sequences", providerId, bboxKey(bbox), zoom],
161
163
  queryFn: ({ signal }) => adapter?.fetchSequences?.(bbox, zoom, signal) ?? [],
@@ -163,10 +165,10 @@ var useProviderSequences = (providerId, bbox, zoom) => {
163
165
  placeholderData: (previous) => previous
164
166
  });
165
167
  };
166
- var useProviderMapFeatures = (providerId, bbox, zoom) => {
168
+ var useProviderMapFeatures = (providerId, bbox, zoom, { minZoom = 0 } = {}) => {
167
169
  const adapter = adapterById[providerId];
168
170
  const meta = providerById[providerId];
169
- const enabled = meta.kind === "mapFeature" && bbox != null && providerCoversBbox(providerId, bbox) && zoom >= meta.minZoom && adapter?.fetchMapFeatures != null;
171
+ const enabled = meta.kind === "mapFeature" && bbox != null && providerCoversBbox(providerId, bbox) && zoom >= Math.max(meta.minZoom, minZoom) && adapter?.fetchMapFeatures != null;
170
172
  return useQuery({
171
173
  queryKey: ["provider-map-features", providerId, bboxKey(bbox), zoom],
172
174
  queryFn: async ({ signal }) => {
@@ -194,7 +196,8 @@ var StreetLevelImageryViewCone = ({
194
196
  zoom,
195
197
  viewerPov,
196
198
  color = SELECTION_COLOR,
197
- scale = 2.5
199
+ scale = 2.5,
200
+ beforeId
198
201
  }) => {
199
202
  const apex = viewerPov?.lngLat ?? selectedPhoto.lngLat;
200
203
  const isPano = selectedPhoto.isPano === true;
@@ -207,6 +210,9 @@ var StreetLevelImageryViewCone = ({
207
210
  } else if (selectedPhoto.providerId === "panoramax") {
208
211
  bearing = viewerPov?.bearing ?? selectedPhoto.heading;
209
212
  fov = 30;
213
+ } else if (selectedPhoto.providerId === "mapillary") {
214
+ bearing = viewerPov?.bearing ?? selectedPhoto.heading;
215
+ fov = viewerPov?.hfov ?? 30;
210
216
  } else {
211
217
  bearing = selectedPhoto.heading;
212
218
  fov = 30;
@@ -224,6 +230,7 @@ var StreetLevelImageryViewCone = ({
224
230
  /* @__PURE__ */ jsx(
225
231
  Layer,
226
232
  {
233
+ beforeId,
227
234
  id: CONE_FILL_LAYER_ID,
228
235
  type: "fill",
229
236
  source: CONE_SOURCE_ID,
@@ -271,6 +278,7 @@ var AGE_SHADE = [
271
278
  BASE_COLOR
272
279
  ]
273
280
  ];
281
+ var PHOTO_TARGET_RADIUS_PX = 10;
274
282
  var PHOTO_SORT_KEY = ["coalesce", ["get", "capturedAt"], 0];
275
283
  var FEATURE_SORT_KEY = ["coalesce", ["get", "lastSeenAt"], 0];
276
284
  var PhotoProviderLayer = ({
@@ -283,15 +291,20 @@ var PhotoProviderLayer = ({
283
291
  photoCircleColor,
284
292
  activeSequenceId,
285
293
  hasActiveSequence,
286
- shownPhotoId
294
+ shownPhotoId,
295
+ beforeId,
296
+ minZoom
287
297
  }) => {
288
298
  const adapter = adapterById[providerId];
289
299
  const meta = providerById[providerId];
290
- const { data: photos = [] } = useProviderPhotos(providerId, bbox, zoom);
291
- const { data: sequences = [] } = useProviderSequences(providerId, bbox, zoom);
292
- const visiblePhotos = zoom >= meta.minZoom ? photos.filter((photo) => photoMatchesFilters(photo, filter?.photoTypes, filter?.date)) : [];
300
+ const photosMinZoom = Math.max(meta.minZoom, minZoom);
301
+ const fetchedLinesMinZoom = fetchedSequencesMinZoom(providerId);
302
+ const sequencesMinZoom = Math.max(fetchedLinesMinZoom, minZoom);
303
+ const { data: photos = [] } = useProviderPhotos(providerId, bbox, zoom, { minZoom });
304
+ const { data: sequences = [] } = useProviderSequences(providerId, bbox, zoom, { minZoom });
305
+ const visiblePhotos = zoom >= photosMinZoom ? photos.filter((photo) => photoMatchesFilters(photo, filter?.photoTypes, filter?.date)) : [];
293
306
  const drawBbox = bbox ? padBbox(bbox, 0.25) : null;
294
- const photoCollection = zoom >= meta.minZoom ? photosToFeatureCollection(
307
+ const photoCollection = zoom >= photosMinZoom ? photosToFeatureCollection(
295
308
  drawBbox ? visiblePhotos.filter((photo) => lngLatInBbox(photo.lngLat, drawBbox)) : visiblePhotos
296
309
  ) : emptyPointCollection();
297
310
  const viewfieldsActive = showViewfields && zoom >= VIEWFIELD_MIN_ZOOM;
@@ -342,7 +355,7 @@ var PhotoProviderLayer = ({
342
355
  sequenceCapturedAtById.set(photo.sequenceId, photo.capturedAt);
343
356
  }
344
357
  }
345
- const filteredSequences = showSequences && zoom >= meta.sequencesMinZoom ? sequences.map((sequence) => {
358
+ const filteredSequences = showSequences && zoom >= sequencesMinZoom ? sequences.map((sequence) => {
346
359
  if (sequence.capturedAt != null) return sequence;
347
360
  const fromPhotos = sequenceCapturedAtById.get(sequence.sequenceId);
348
361
  return fromPhotos != null ? { ...sequence, capturedAt: fromPhotos } : sequence;
@@ -385,6 +398,8 @@ var PhotoProviderLayer = ({
385
398
  }
386
399
  };
387
400
  });
401
+ const sequenceTiles = showSequences ? adapter?.sequenceTiles?.() : null;
402
+ const sequenceTilesMinZoom = sequenceTiles ? Math.max(sequenceTiles.minZoom, minZoom) : 0;
388
403
  const sequenceCollection = alignedSequences.length > 0 ? sequencesToFeatureCollection(alignedSequences) : emptyLineCollection();
389
404
  return /* @__PURE__ */ jsxs(Fragment, { children: [
390
405
  meta.coverageTiles ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -401,6 +416,7 @@ var PhotoProviderLayer = ({
401
416
  /* @__PURE__ */ jsx(
402
417
  Layer,
403
418
  {
419
+ beforeId,
404
420
  id: `coverage-tiles-${providerId}`,
405
421
  minzoom: meta.coverageTiles.minZoom,
406
422
  paint: { "raster-opacity": 0.7 },
@@ -409,6 +425,48 @@ var PhotoProviderLayer = ({
409
425
  }
410
426
  )
411
427
  ] }) : null,
428
+ sequenceTiles && sequenceTilesMinZoom < fetchedLinesMinZoom ? /* @__PURE__ */ jsxs(Fragment, { children: [
429
+ /* @__PURE__ */ jsx(
430
+ Source,
431
+ {
432
+ id: sequenceTilesSourceId(providerId),
433
+ type: "vector",
434
+ tiles: sequenceTiles.tiles,
435
+ minzoom: sequenceTiles.minZoom,
436
+ maxzoom: sequenceTiles.maxZoom
437
+ },
438
+ sequenceTilesSourceId(providerId)
439
+ ),
440
+ /* @__PURE__ */ jsx(
441
+ Layer,
442
+ {
443
+ beforeId,
444
+ id: sequenceTilesLayerId(providerId),
445
+ type: "line",
446
+ source: sequenceTilesSourceId(providerId),
447
+ "source-layer": sequenceTiles.sourceLayer,
448
+ minzoom: sequenceTilesMinZoom,
449
+ maxzoom: fetchedLinesMinZoom,
450
+ filter: renameExpressionProperties(photoFilter, sequenceTiles.properties),
451
+ layout: {
452
+ "line-cap": "round",
453
+ "line-join": "round",
454
+ "line-sort-key": renameExpressionProperties(
455
+ ["case", inActiveSequence, 1, 0],
456
+ sequenceTiles.properties
457
+ )
458
+ },
459
+ paint: {
460
+ "line-color": renameExpressionProperties(photoCircleColor, sequenceTiles.properties),
461
+ "line-width": renameExpressionProperties(
462
+ ["case", inActiveSequence, ACTIVE_LINE_WIDTH, 1.25],
463
+ sequenceTiles.properties
464
+ ),
465
+ "line-opacity": renameExpressionProperties(lineOpacity, sequenceTiles.properties)
466
+ }
467
+ }
468
+ )
469
+ ] }) : null,
412
470
  adapter?.fetchSequences && showSequences ? /* @__PURE__ */ jsxs(Fragment, { children: [
413
471
  /* @__PURE__ */ jsx(
414
472
  Source,
@@ -422,6 +480,7 @@ var PhotoProviderLayer = ({
422
480
  /* @__PURE__ */ jsx(
423
481
  Layer,
424
482
  {
483
+ beforeId,
425
484
  id: sequenceLayerId(providerId),
426
485
  type: "line",
427
486
  source: sequenceSourceId(providerId),
@@ -451,6 +510,7 @@ var PhotoProviderLayer = ({
451
510
  /* @__PURE__ */ jsx(
452
511
  Layer,
453
512
  {
513
+ beforeId,
454
514
  id: viewfieldLayerId(providerId),
455
515
  type: "fill",
456
516
  source: viewfieldSrcId,
@@ -465,6 +525,7 @@ var PhotoProviderLayer = ({
465
525
  /* @__PURE__ */ jsx(
466
526
  Layer,
467
527
  {
528
+ beforeId,
468
529
  id: viewfieldLineLayerId(providerId),
469
530
  type: "line",
470
531
  source: viewfieldSrcId,
@@ -490,6 +551,19 @@ var PhotoProviderLayer = ({
490
551
  /* @__PURE__ */ jsx(
491
552
  Layer,
492
553
  {
554
+ beforeId,
555
+ id: photoTargetLayerId(providerId),
556
+ type: "circle",
557
+ source: photoSrcId,
558
+ filter: photoFilter,
559
+ layout: { "circle-sort-key": PHOTO_SORT_KEY },
560
+ paint: { "circle-radius": PHOTO_TARGET_RADIUS_PX, "circle-opacity": 0 }
561
+ }
562
+ ),
563
+ /* @__PURE__ */ jsx(
564
+ Layer,
565
+ {
566
+ beforeId,
493
567
  id: photoLayerId(providerId),
494
568
  type: "circle",
495
569
  source: photoSrcId,
@@ -508,12 +582,14 @@ var MapFeatureProviderLayer = ({
508
582
  bbox,
509
583
  zoom,
510
584
  filter,
511
- mapFeatureCircleColor
585
+ mapFeatureCircleColor,
586
+ beforeId,
587
+ minZoom
512
588
  }) => {
513
589
  const meta = providerById[providerId];
514
- const { data: features = [] } = useProviderMapFeatures(providerId, bbox, zoom);
590
+ const { data: features = [] } = useProviderMapFeatures(providerId, bbox, zoom, { minZoom });
515
591
  const valueFilter = filter?.mapFeatureValue;
516
- const featureCollection = zoom >= meta.minZoom ? mapFeaturesToFeatureCollection(
592
+ const featureCollection = zoom >= Math.max(meta.minZoom, minZoom) ? mapFeaturesToFeatureCollection(
517
593
  valueFilter ? features.filter((feature) => valueFilter(feature.value)) : features
518
594
  ) : emptyPointCollection();
519
595
  const featureFilter = buildMapFeatureLayerFilter(filter?.date);
@@ -532,6 +608,7 @@ var MapFeatureProviderLayer = ({
532
608
  /* @__PURE__ */ jsx(
533
609
  Layer,
534
610
  {
611
+ beforeId,
535
612
  id: featureLayerId(providerId),
536
613
  type: "circle",
537
614
  source: featureSrcId,
@@ -567,7 +644,9 @@ var StreetLevelImagerySourcesAndLayers = ({
567
644
  viewConeColor,
568
645
  viewConeScale,
569
646
  photoCircleColor,
570
- mapFeatureCircleColor
647
+ mapFeatureCircleColor,
648
+ beforeId,
649
+ minZoom = 0
571
650
  } = options;
572
651
  useEffect(
573
652
  function applyStreetImageryConfig() {
@@ -594,6 +673,8 @@ var StreetLevelImagerySourcesAndLayers = ({
594
673
  providers.map((providerId) => /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(
595
674
  ProviderLayer,
596
675
  {
676
+ beforeId,
677
+ minZoom,
597
678
  bbox,
598
679
  filter,
599
680
  mapFeatureCircleColor,
@@ -610,6 +691,7 @@ var StreetLevelImagerySourcesAndLayers = ({
610
691
  showViewCone && selectedPhoto ? /* @__PURE__ */ jsx(
611
692
  StreetLevelImageryViewCone,
612
693
  {
694
+ beforeId,
613
695
  color: viewConeColor ?? SELECTION_COLOR,
614
696
  scale: viewConeScale,
615
697
  selectedPhoto,
@@ -620,6 +702,7 @@ var StreetLevelImagerySourcesAndLayers = ({
620
702
  showSelectionHighlight ? /* @__PURE__ */ jsx(
621
703
  StreetLevelImagerySelectionOverlay,
622
704
  {
705
+ beforeId,
623
706
  cameraLngLat: viewerPov?.lngLat,
624
707
  selectedPhoto,
625
708
  selectedSequence: providerDrawsSequences ? null : selectedSequence,
@@ -628,13 +711,13 @@ var StreetLevelImagerySourcesAndLayers = ({
628
711
  ) : null
629
712
  ] });
630
713
  };
631
- var MapillaryPanel2 = lazy(
632
- () => import('./MapillaryPanel-N45NQY4C.js').then((module) => ({
714
+ var MapillaryPanel = lazy(
715
+ () => import('./MapillaryPanel-FAXVZH37.js').then((module) => ({
633
716
  default: module.MapillaryPanel
634
717
  }))
635
718
  );
636
- var PanoramaxPanel2 = lazy(
637
- () => import('./PanoramaxPanel-MFI4L67Z.js').then((module) => ({
719
+ var PanoramaxPanel = lazy(
720
+ () => import('./PanoramaxPanel-BTHEMKYY.js').then((module) => ({
638
721
  default: module.PanoramaxPanel
639
722
  }))
640
723
  );
@@ -655,7 +738,7 @@ var StreetLevelImageryViewer = ({
655
738
  }) => {
656
739
  if (photo.providerId === "mapillary") {
657
740
  return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(ViewerPanelPlaceholder, {}), children: /* @__PURE__ */ jsx(
658
- MapillaryPanel2,
741
+ MapillaryPanel,
659
742
  {
660
743
  groupPhotos,
661
744
  hideAttribution,
@@ -671,7 +754,7 @@ var StreetLevelImageryViewer = ({
671
754
  }
672
755
  if (photo.providerId === "panoramax") {
673
756
  return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(ViewerPanelPlaceholder, {}), children: /* @__PURE__ */ jsx(
674
- PanoramaxPanel2,
757
+ PanoramaxPanel,
675
758
  {
676
759
  groupPhotos,
677
760
  hideLegend: hideAttribution,
@@ -686,6 +769,7 @@ var StreetLevelImageryViewer = ({
686
769
  };
687
770
  var streetImageryInteractiveLayerIds = (providers) => [
688
771
  ...providers.map((providerId) => photoLayerId(providerId)),
772
+ ...providers.map((providerId) => photoTargetLayerId(providerId)),
689
773
  ...providers.map((providerId) => viewfieldLayerId(providerId)),
690
774
  ...providers.map((providerId) => featureLayerId(providerId))
691
775
  ];
@@ -694,6 +778,10 @@ var parseProviderIdFromLayerId = (layerId) => {
694
778
  if (photoMatch) {
695
779
  return photoMatch[1];
696
780
  }
781
+ const targetMatch = layerId.match(/^photo-targets-(.+)$/);
782
+ if (targetMatch) {
783
+ return targetMatch[1];
784
+ }
697
785
  const viewfieldMatch = layerId.match(/^viewfields-(.+)$/);
698
786
  if (viewfieldMatch) {
699
787
  return viewfieldMatch[1];
@@ -718,7 +806,7 @@ var queryStreetImageryFeatures = (event) => {
718
806
  continue;
719
807
  }
720
808
  const props = feature.properties ?? {};
721
- if (layerId.startsWith("photos-") || layerId.startsWith("viewfields-")) {
809
+ if (layerId.startsWith("photos-") || layerId.startsWith("photo-targets-") || layerId.startsWith("viewfields-")) {
722
810
  const photoId = props.photoId;
723
811
  if (photoId == null) {
724
812
  continue;
@@ -880,6 +968,13 @@ var viewSuggestionLabel = ({ viewpoint, direction }, messages) => messages.viewD
880
968
  var DEFAULT_LAYOUT = { right: 16, bottom: 32, width: 420, minimized: false };
881
969
  var MIN_WIDTH = 280;
882
970
  var EDGE = 8;
971
+ var hasStoredLayout = (storageKey) => {
972
+ try {
973
+ return localStorage.getItem(storageKey) != null;
974
+ } catch {
975
+ return false;
976
+ }
977
+ };
883
978
  var readLayout = (storageKey) => {
884
979
  try {
885
980
  const raw = localStorage.getItem(storageKey);
@@ -1024,8 +1119,8 @@ var FloatingPhotoViewer = ({
1024
1119
  activeDirectionKey,
1025
1120
  onSelectSuggestion,
1026
1121
  shownPhotoId,
1027
- canGoBack,
1028
- canGoForward,
1122
+ canGoBack = false,
1123
+ canGoForward = false,
1029
1124
  onBack,
1030
1125
  onForward,
1031
1126
  onClose,
@@ -1035,12 +1130,16 @@ var FloatingPhotoViewer = ({
1035
1130
  children,
1036
1131
  footer,
1037
1132
  drawer,
1038
- storageKey = "street-imagery:floating-viewer"
1133
+ storageKey = "street-imagery:floating-viewer",
1134
+ defaultPosition
1039
1135
  }) => {
1040
1136
  const { messages } = useStreetImageryI18n();
1041
1137
  const severalViewpoints = new Set(suggestions.map((suggestion) => suggestion.viewpoint.id)).size > 1;
1042
1138
  const [layout, setLayout] = useState(() => readLayout(storageKey));
1043
1139
  const [drawerOpen, setDrawerOpen] = useState(false);
1140
+ const [moved, setMoved] = useState(() => hasStoredLayout(storageKey));
1141
+ const atTopLeft = defaultPosition?.corner === "top-left" && !moved;
1142
+ const position = atTopLeft ? { left: defaultPosition.left ?? EDGE, top: defaultPosition.top ?? EDGE } : { right: layout.right, bottom: layout.bottom };
1044
1143
  const dragRef = useRef(null);
1045
1144
  const updateLayout = (next) => {
1046
1145
  setLayout(next);
@@ -1054,9 +1153,9 @@ var FloatingPhotoViewer = ({
1054
1153
  if (event.key === "Escape") {
1055
1154
  onClose();
1056
1155
  } else if (event.key === "[" && canGoBack) {
1057
- onBack();
1156
+ onBack?.();
1058
1157
  } else if (event.key === "]" && canGoForward) {
1059
- onForward();
1158
+ onForward?.();
1060
1159
  } else if (event.key === "ArrowLeft" && event.altKey) {
1061
1160
  step?.onPrevious?.();
1062
1161
  } else if (event.key === "ArrowRight" && event.altKey) {
@@ -1072,7 +1171,16 @@ var FloatingPhotoViewer = ({
1072
1171
  return;
1073
1172
  }
1074
1173
  event.currentTarget.setPointerCapture(event.pointerId);
1075
- dragRef.current = { x: event.clientX, y: event.clientY, layout, mode };
1174
+ const box = event.currentTarget.closest("section");
1175
+ const container = box?.offsetParent;
1176
+ const start = atTopLeft && box && container ? {
1177
+ ...layout,
1178
+ right: container.clientWidth - box.offsetLeft - box.offsetWidth,
1179
+ bottom: container.clientHeight - box.offsetTop - box.offsetHeight
1180
+ } : layout;
1181
+ setLayout(start);
1182
+ setMoved(true);
1183
+ dragRef.current = { x: event.clientX, y: event.clientY, layout: start, mode };
1076
1184
  };
1077
1185
  const onDrag = (event) => {
1078
1186
  const drag = dragRef.current;
@@ -1102,7 +1210,7 @@ var FloatingPhotoViewer = ({
1102
1210
  {
1103
1211
  className: "absolute z-10 inline-flex items-center gap-2 rounded-full bg-white px-3 py-1.5 text-sm font-medium text-slate-800 shadow-lg ring-1 ring-slate-200 hover:bg-slate-50",
1104
1212
  onClick: () => updateLayout({ ...layout, minimized: false }),
1105
- style: { right: layout.right, bottom: layout.bottom },
1213
+ style: position,
1106
1214
  type: "button",
1107
1215
  children: [
1108
1216
  /* @__PURE__ */ jsx(Icon, { path: ICONS.expand }),
@@ -1117,8 +1225,7 @@ var FloatingPhotoViewer = ({
1117
1225
  "aria-label": messages.viewer.regionLabel,
1118
1226
  className: "absolute z-10 flex max-h-[calc(100%-1rem)] flex-col overflow-hidden rounded-xl bg-white shadow-xl ring-1 ring-slate-200",
1119
1227
  style: {
1120
- right: layout.right,
1121
- bottom: layout.bottom,
1228
+ ...position,
1122
1229
  width: `min(${layout.width}px, calc(100% - 1rem))`
1123
1230
  },
1124
1231
  children: [
@@ -1162,16 +1269,26 @@ var FloatingPhotoViewer = ({
1162
1269
  /* @__PURE__ */ jsx("h2", { className: "min-w-0 truncate px-1 text-sm font-semibold text-slate-800", children: title }),
1163
1270
  titleActions
1164
1271
  ] }),
1165
- /* @__PURE__ */ jsx(ToolbarButton, { disabled: !canGoBack, label: messages.viewer.backInHistory, onClick: onBack, children: /* @__PURE__ */ jsx(Icon, { path: ICONS.undo }) }),
1166
- /* @__PURE__ */ jsx(
1167
- ToolbarButton,
1168
- {
1169
- disabled: !canGoForward,
1170
- label: messages.viewer.forwardInHistory,
1171
- onClick: onForward,
1172
- children: /* @__PURE__ */ jsx(Icon, { path: ICONS.redo })
1173
- }
1174
- ),
1272
+ onBack && onForward ? /* @__PURE__ */ jsxs(Fragment, { children: [
1273
+ /* @__PURE__ */ jsx(
1274
+ ToolbarButton,
1275
+ {
1276
+ disabled: !canGoBack,
1277
+ label: messages.viewer.backInHistory,
1278
+ onClick: onBack,
1279
+ children: /* @__PURE__ */ jsx(Icon, { path: ICONS.undo })
1280
+ }
1281
+ ),
1282
+ /* @__PURE__ */ jsx(
1283
+ ToolbarButton,
1284
+ {
1285
+ disabled: !canGoForward,
1286
+ label: messages.viewer.forwardInHistory,
1287
+ onClick: onForward,
1288
+ children: /* @__PURE__ */ jsx(Icon, { path: ICONS.redo })
1289
+ }
1290
+ )
1291
+ ] }) : null,
1175
1292
  /* @__PURE__ */ jsx(
1176
1293
  ToolbarButton,
1177
1294
  {
@@ -1484,6 +1601,20 @@ var useMapillaryImageDetections = (imageId, { filter, filterKey } = {}) => useQu
1484
1601
  enabled: !!imageId,
1485
1602
  staleTime: STALE_TIME
1486
1603
  });
1604
+ var useSelectedMapillaryFeature = ({
1605
+ featureId,
1606
+ shownPhotoId,
1607
+ minCapturedAt,
1608
+ shape
1609
+ }) => {
1610
+ const { data, isLoading, isError } = useMapillaryMapFeatureImages(featureId, { shape });
1611
+ const shownImage = data?.images.find((image) => image.id === shownPhotoId) ?? null;
1612
+ const firstImage = data ? bestTargetImage(data.images, data.feature.lngLat, {
1613
+ minCapturedAt: minCapturedAt ?? void 0,
1614
+ shape
1615
+ }) ?? null : null;
1616
+ return { data: data ?? null, isLoading, isError, shownImage, firstImage };
1617
+ };
1487
1618
  var useLocationPickStore = create()((set) => ({
1488
1619
  armedOpenerId: null,
1489
1620
  actions: {
@@ -1535,6 +1666,70 @@ var LocationPickOnMap = ({ onPick }) => {
1535
1666
  );
1536
1667
  return null;
1537
1668
  };
1669
+ var SelectedMapFeatureLayer = ({
1670
+ data,
1671
+ shownImage,
1672
+ providers,
1673
+ bbox,
1674
+ zoom,
1675
+ color = MAP_FEATURE_COLOR
1676
+ }) => {
1677
+ const drawnFeatures = useAllProviderMapFeatures(providers, bbox, zoom);
1678
+ const target = data ? drawnFeatures.find((feature) => feature.featureId === data.feature.id)?.lngLat ?? data.feature.lngLat : null;
1679
+ const camera = shownImage?.lngLat;
1680
+ const points = {
1681
+ type: "FeatureCollection",
1682
+ features: target ? [{ type: "Feature", properties: {}, geometry: { type: "Point", coordinates: target } }] : []
1683
+ };
1684
+ const line = {
1685
+ type: "FeatureCollection",
1686
+ features: target && camera ? [
1687
+ {
1688
+ type: "Feature",
1689
+ properties: {},
1690
+ geometry: { type: "LineString", coordinates: [camera, target] }
1691
+ }
1692
+ ] : []
1693
+ };
1694
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1695
+ /* @__PURE__ */ jsx(Source, { data: line, id: "selected-map-feature-line", type: "geojson" }),
1696
+ /* @__PURE__ */ jsx(
1697
+ Layer,
1698
+ {
1699
+ id: "selected-map-feature-line",
1700
+ paint: { "line-color": SELECTION_COLOR, "line-width": 1.5, "line-dasharray": [2, 1.5] },
1701
+ source: "selected-map-feature-line",
1702
+ type: "line"
1703
+ }
1704
+ ),
1705
+ /* @__PURE__ */ jsx(Source, { data: points, id: "selected-map-feature-point", type: "geojson" }),
1706
+ /* @__PURE__ */ jsx(
1707
+ Layer,
1708
+ {
1709
+ id: "selected-map-feature-disk",
1710
+ paint: {
1711
+ "circle-radius": 17,
1712
+ "circle-color": color,
1713
+ "circle-opacity": VIEW_SHAPE_FILL_OPACITY
1714
+ },
1715
+ source: "selected-map-feature-point",
1716
+ type: "circle"
1717
+ }
1718
+ ),
1719
+ /* @__PURE__ */ jsx(
1720
+ Layer,
1721
+ {
1722
+ id: "selected-map-feature-dot",
1723
+ paint: {
1724
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 10, 1.8, 14, 3.6, 18, 4.8],
1725
+ "circle-color": color
1726
+ },
1727
+ source: "selected-map-feature-point",
1728
+ type: "circle"
1729
+ }
1730
+ )
1731
+ ] });
1732
+ };
1538
1733
  var MAPILLARY_FEATURE_BAR_LABELS = {
1539
1734
  en: {
1540
1735
  name: (value) => mapillaryValueName(value, "en"),
@@ -1630,5 +1825,234 @@ ${labels.dayPhotos(day.images.length, active && day.images.length > 1)}`,
1630
1825
  )
1631
1826
  ] });
1632
1827
  };
1828
+ var DEFAULT_YEAR_LINES = [1, 2, 3, 4];
1829
+ var BINS = 60;
1830
+ var STEP = 1e-3;
1831
+ var CHART_HEIGHT_PX = 36;
1832
+ var RED = "#dc2626";
1833
+ var HANDLE_CLASS = "pointer-events-none absolute inset-0 m-0 h-full w-full cursor-pointer appearance-none bg-transparent focus:outline-none [&::-webkit-slider-runnable-track]:appearance-none [&::-webkit-slider-runnable-track]:bg-transparent [&::-moz-range-track]:bg-transparent [&::-webkit-slider-thumb]:pointer-events-auto [&::-webkit-slider-thumb]:size-4 [&::-webkit-slider-thumb]:cursor-grab [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-white [&::-webkit-slider-thumb]:bg-slate-800 [&::-webkit-slider-thumb]:shadow [&::-moz-range-thumb]:pointer-events-auto [&::-moz-range-thumb]:box-border [&::-moz-range-thumb]:size-4 [&::-moz-range-thumb]:cursor-grab [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-white [&::-moz-range-thumb]:bg-slate-800 [&::-moz-range-thumb]:shadow focus-visible:[&::-webkit-slider-thumb]:ring-2 focus-visible:[&::-webkit-slider-thumb]:ring-sky-500 focus-visible:[&::-moz-range-thumb]:ring-2 focus-visible:[&::-moz-range-thumb]:ring-sky-500";
1834
+ var percent = (position) => `${position * 100}%`;
1835
+ var PhotoDateRangeFilter = ({
1836
+ value,
1837
+ onChange,
1838
+ capturedAt,
1839
+ yearLines = DEFAULT_YEAR_LINES,
1840
+ recommendedMaxAgeYears,
1841
+ markers = [],
1842
+ maxYears,
1843
+ now: nowProp,
1844
+ dateInputs = "collapsed",
1845
+ className,
1846
+ allDatesAction = true
1847
+ }) => {
1848
+ const { locale, messages } = useStreetImageryI18n();
1849
+ const text = messages.dateFilter;
1850
+ const [startNow] = useState(() => Date.now());
1851
+ const now = nowProp ?? startNow;
1852
+ const scale = { now, maxYears };
1853
+ const [dragged, setDragged] = useState(null);
1854
+ const fromInput = useRef(null);
1855
+ const toInput = useRef(null);
1856
+ const positions = dragged ?? dateRangeToSliderPositions(value, scale);
1857
+ const shownRange = dragged ? sliderPositionsToDateRange(dragged, scale) : value;
1858
+ const readPositions = (moved) => {
1859
+ const from = Number(fromInput.current?.value ?? positions.from);
1860
+ const to = Number(toInput.current?.value ?? positions.to);
1861
+ return moved === "from" ? { from: Math.min(from, to), to } : { from, to: Math.max(from, to) };
1862
+ };
1863
+ const commitOnRelease = (moved) => (input) => {
1864
+ if (!input) {
1865
+ return void 0;
1866
+ }
1867
+ const commit = () => {
1868
+ setDragged(null);
1869
+ const next = sliderPositionsToDateRange(readPositions(moved), scale);
1870
+ const other = moved === "from" ? "to" : "from";
1871
+ onChange({ ...next, [other]: value[other] });
1872
+ };
1873
+ input.addEventListener("change", commit);
1874
+ return () => {
1875
+ input.removeEventListener("change", commit);
1876
+ };
1877
+ };
1878
+ const trackDrag = (moved, event) => {
1879
+ if (event.type === "input") {
1880
+ setDragged(readPositions(moved));
1881
+ }
1882
+ };
1883
+ const bins = capturedAt ? dateSliderBins(capturedAt, scale, BINS) : [];
1884
+ const maxCount = Math.max(1, ...bins);
1885
+ const years = [
1886
+ ...new Set(recommendedMaxAgeYears ? [...yearLines, recommendedMaxAgeYears] : yearLines)
1887
+ ].map((count) => ({ count, position: dateSliderPosition(yearsAgoMs(count, now), scale) })).filter(({ position }) => position > 0 && position < 1);
1888
+ const shownMarkers = markers.map((marker) => {
1889
+ const time = typeof marker.date === "number" ? marker.date : parseIsoDateStartMs(marker.date);
1890
+ return { ...marker, position: dateSliderPosition(time, scale) };
1891
+ }).filter(({ position }) => position > 0 && position < 1);
1892
+ const day = (isoDate) => formatDate(parseIsoDateStartMs(isoDate), locale);
1893
+ const rangeLabel = shownRange.from && shownRange.to ? text.between(day(shownRange.from), day(shownRange.to)) : shownRange.from ? text.since(day(shownRange.from)) : shownRange.to ? text.until(day(shownRange.to)) : text.allDates;
1894
+ const setYears = (count) => {
1895
+ onChange({ from: new Date(yearsAgoMs(count, now)).toISOString().slice(0, 10) });
1896
+ };
1897
+ const setDay = (key, input) => {
1898
+ if (input === "") {
1899
+ onChange({ ...value, [key]: void 0 });
1900
+ } else if (isIsoDate(input)) {
1901
+ onChange({ ...value, [key]: input });
1902
+ }
1903
+ };
1904
+ const isAllDates = !shownRange.from && !shownRange.to;
1905
+ return /* @__PURE__ */ jsxs("div", { className, children: [
1906
+ /* @__PURE__ */ jsx("div", { className: "mx-2", children: /* @__PURE__ */ jsxs(
1907
+ "div",
1908
+ {
1909
+ className: "relative",
1910
+ style: { height: CHART_HEIGHT_PX, marginTop: shownMarkers.length > 0 ? 14 : 0 },
1911
+ children: [
1912
+ /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "absolute inset-0 flex items-end", children: bins.map((count, index) => {
1913
+ const start = index / BINS;
1914
+ const inRange = start + 1 / BINS > positions.from && start < positions.to;
1915
+ return /* @__PURE__ */ jsx(
1916
+ "div",
1917
+ {
1918
+ className: `flex-1 rounded-t-[1px] ${inRange ? "bg-slate-500" : "bg-slate-300"}`,
1919
+ style: {
1920
+ height: count === 0 ? 0 : Math.max(2, Math.log1p(count) / Math.log1p(maxCount) * CHART_HEIGHT_PX)
1921
+ },
1922
+ title: count > 0 ? text.photoCount(count) : void 0
1923
+ },
1924
+ index
1925
+ );
1926
+ }) }),
1927
+ years.map(({ count, position }) => /* @__PURE__ */ jsx(
1928
+ "div",
1929
+ {
1930
+ "aria-hidden": true,
1931
+ className: "pointer-events-none absolute inset-y-0 w-px -translate-x-1/2",
1932
+ style: {
1933
+ left: percent(position),
1934
+ backgroundColor: count === recommendedMaxAgeYears ? RED : "rgb(148 163 184 / 0.7)"
1935
+ }
1936
+ },
1937
+ count
1938
+ )),
1939
+ shownMarkers.map((marker) => /* @__PURE__ */ jsx(
1940
+ "div",
1941
+ {
1942
+ className: "pointer-events-none absolute inset-y-0 w-0 border-l-2 border-dashed",
1943
+ style: { left: percent(marker.position), borderColor: marker.color ?? RED },
1944
+ children: /* @__PURE__ */ jsx(
1945
+ "span",
1946
+ {
1947
+ className: "absolute -top-3.5 -translate-x-1/2 text-[10px] leading-none whitespace-nowrap",
1948
+ style: { color: marker.color ?? RED },
1949
+ children: marker.label
1950
+ }
1951
+ )
1952
+ },
1953
+ `${marker.date}-${marker.label}`
1954
+ ))
1955
+ ]
1956
+ }
1957
+ ) }),
1958
+ /* @__PURE__ */ jsxs("div", { className: "relative h-4", children: [
1959
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-x-2 top-1/2 h-1 -translate-y-1/2 rounded-full bg-slate-200", children: /* @__PURE__ */ jsx(
1960
+ "div",
1961
+ {
1962
+ className: "absolute inset-y-0 rounded-full bg-slate-700",
1963
+ style: {
1964
+ left: percent(positions.from),
1965
+ right: percent(1 - positions.to)
1966
+ }
1967
+ }
1968
+ ) }),
1969
+ /* @__PURE__ */ jsx(
1970
+ "input",
1971
+ {
1972
+ "aria-label": text.fromHandle,
1973
+ "aria-valuetext": shownRange.from ? day(shownRange.from) : text.allDates,
1974
+ className: HANDLE_CLASS,
1975
+ max: 1,
1976
+ min: 0,
1977
+ onChange: (event) => {
1978
+ trackDrag("from", event.nativeEvent);
1979
+ },
1980
+ ref: (input) => {
1981
+ fromInput.current = input;
1982
+ return commitOnRelease("from")(input);
1983
+ },
1984
+ step: STEP,
1985
+ type: "range",
1986
+ value: positions.from
1987
+ }
1988
+ ),
1989
+ /* @__PURE__ */ jsx(
1990
+ "input",
1991
+ {
1992
+ "aria-label": text.toHandle,
1993
+ "aria-valuetext": shownRange.to ? day(shownRange.to) : text.allDates,
1994
+ className: HANDLE_CLASS,
1995
+ max: 1,
1996
+ min: 0,
1997
+ onChange: (event) => {
1998
+ trackDrag("to", event.nativeEvent);
1999
+ },
2000
+ ref: (input) => {
2001
+ toInput.current = input;
2002
+ return commitOnRelease("to")(input);
2003
+ },
2004
+ step: STEP,
2005
+ type: "range",
2006
+ value: positions.to
2007
+ }
2008
+ )
2009
+ ] }),
2010
+ /* @__PURE__ */ jsx("div", { className: "relative mx-2 h-4", children: years.map(({ count, position }) => /* @__PURE__ */ jsx(
2011
+ "button",
2012
+ {
2013
+ className: `absolute top-0 -translate-x-1/2 rounded px-0.5 text-[10px] leading-4 whitespace-nowrap hover:underline ${count === recommendedMaxAgeYears ? "font-semibold text-red-600" : "text-slate-500 hover:text-slate-900"}`,
2014
+ onClick: () => {
2015
+ setYears(count);
2016
+ },
2017
+ style: { left: percent(position) },
2018
+ title: count === recommendedMaxAgeYears ? text.recommendedMaxAge(count) : text.lastYears(count),
2019
+ type: "button",
2020
+ children: text.yearsShort(count)
2021
+ },
2022
+ count
2023
+ )) }),
2024
+ /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-baseline justify-between gap-2 text-xs", children: [
2025
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-slate-700", children: rangeLabel }),
2026
+ isAllDates || !allDatesAction ? null : /* @__PURE__ */ jsx(
2027
+ "button",
2028
+ {
2029
+ className: "shrink-0 font-medium text-slate-600 underline decoration-slate-300 underline-offset-2 hover:text-slate-900",
2030
+ onClick: () => {
2031
+ onChange({});
2032
+ },
2033
+ type: "button",
2034
+ children: text.allDates
2035
+ }
2036
+ )
2037
+ ] }),
2038
+ dateInputs === "none" ? null : /* @__PURE__ */ jsxs("details", { className: "mt-1 text-xs text-slate-600", open: dateInputs === "open" || void 0, children: [
2039
+ /* @__PURE__ */ jsx("summary", { className: "cursor-pointer select-none hover:text-slate-900", children: text.exactDates }),
2040
+ /* @__PURE__ */ jsx("div", { className: "mt-1.5 grid grid-cols-2 gap-2", children: ["from", "to"].map((key) => /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
2041
+ text[key],
2042
+ /* @__PURE__ */ jsx(
2043
+ "input",
2044
+ {
2045
+ className: "rounded-md border border-slate-200 px-2 py-1.5 text-sm text-slate-800",
2046
+ onChange: (event) => {
2047
+ setDay(key, event.target.value);
2048
+ },
2049
+ type: "date",
2050
+ value: value[key] ?? ""
2051
+ }
2052
+ )
2053
+ ] }, key)) })
2054
+ ] })
2055
+ ] });
2056
+ };
1633
2057
 
1634
- export { BASE_COLOR, FloatingPhotoViewer, FloatingViewerInfoButton, LocationPickOnMap, MAPILLARY_FEATURE_BAR_LABELS, MapillaryFeatureBar, PhotoCount, PhotoDate, SELECTION_COLOR, StreetLevelImagerySelectionOverlay, StreetLevelImagerySourcesAndLayers, StreetLevelImageryViewCone, StreetLevelImageryViewer, VIEWPOINT_DEFAULT_COLOR, VIEWPOINT_DIRECTION_LAYER_ID, VIEW_SHAPE_FILL_OPACITY, ViewpointLayer, getViewpointSession, queryStreetImageryFeatures, resolveSelectedSequence, streetImageryInteractiveLayerIds, useActiveDirectionKey, useAllProviderMapFeatures, useAllProviderPhotos, useArmedLocationOpenerId, useCanGoBack, useCanGoForward, useCurrentHistoryEntry, useLocationPickActions, useMapViewportBbox, useMapillaryImageDetections, useMapillaryMapFeatureImages, useMapillaryMapFeaturesNear, usePhotoFullUrl, usePhotoThumbnail, useProviderMapFeatures, useProviderPhotos, useProviderSequences, useViewSuggestions, useViewpointLine, useViewpoints, viewDirectionKeyFromFeatures, viewSuggestionLabel };
2058
+ export { BASE_COLOR, FloatingPhotoViewer, FloatingViewerInfoButton, LocationPickOnMap, MAPILLARY_FEATURE_BAR_LABELS, MapillaryFeatureBar, PhotoCount, PhotoDate, PhotoDateRangeFilter, SELECTION_COLOR, SelectedMapFeatureLayer, StreetLevelImagerySelectionOverlay, StreetLevelImagerySourcesAndLayers, StreetLevelImageryViewCone, StreetLevelImageryViewer, VIEWPOINT_DEFAULT_COLOR, VIEWPOINT_DIRECTION_LAYER_ID, VIEW_SHAPE_FILL_OPACITY, ViewpointLayer, getViewpointSession, queryStreetImageryFeatures, resolveSelectedSequence, streetImageryInteractiveLayerIds, useActiveDirectionKey, useAllProviderMapFeatures, useAllProviderPhotos, useArmedLocationOpenerId, useCanGoBack, useCanGoForward, useCurrentHistoryEntry, useLocationPickActions, useMapViewportBbox, useMapillaryImageDetections, useMapillaryMapFeatureImages, useMapillaryMapFeaturesNear, usePhotoFullUrl, usePhotoThumbnail, useProviderMapFeatures, useProviderPhotos, useProviderSequences, useSelectedMapillaryFeature, useViewSuggestions, useViewpointLine, useViewpoints, viewDirectionKeyFromFeatures, viewSuggestionLabel };