@osm-editor-kit/street-imagery-react 0.1.0-alpha.1 → 0.1.0-alpha.11

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 (52) hide show
  1. package/README.md +178 -3
  2. package/dist/MapillaryPanel-FAXVZH37.js +2 -0
  3. package/dist/PanoramaxPanel-TWKTSOXM.js +2 -0
  4. package/dist/StreetLevelImagerySelectionOverlay.d.ts +22 -3
  5. package/dist/StreetLevelImagerySourcesAndLayers.d.ts +24 -1
  6. package/dist/StreetLevelImageryViewCone.d.ts +13 -1
  7. package/dist/StreetLevelImageryViewer.d.ts +23 -1
  8. package/dist/chunk-6EMFFIL2.js +147 -0
  9. package/dist/chunk-SGIB7AVC.js +309 -0
  10. package/dist/chunk-XQXYV6SR.js +466 -0
  11. package/dist/filters/PhotoDateRangeFilter.d.ts +46 -0
  12. package/dist/hooks/useAllProviderMapFeatures.d.ts +0 -4
  13. package/dist/hooks/useProviderData.d.ts +14 -3
  14. package/dist/i18n/PhotoCount.d.ts +12 -0
  15. package/dist/i18n/PhotoDate.d.ts +16 -0
  16. package/dist/i18n/StreetImageryLocaleProvider.d.ts +21 -0
  17. package/dist/i18n/messages.d.ts +45 -0
  18. package/dist/index.d.ts +19 -4
  19. package/dist/index.js +1546 -144
  20. package/dist/mapillary/MapillaryFeatureBar.d.ts +16 -0
  21. package/dist/mapillary/SelectedMapFeatureLayer.d.ts +19 -0
  22. package/dist/mapillary/featureBarLabels.d.ts +16 -0
  23. package/dist/mapillary/useMapillaryFeatures.d.ts +54 -0
  24. package/dist/openers/LocationPickOnMap.d.ts +10 -0
  25. package/dist/openers/useLocationPickStore.d.ts +9 -0
  26. package/dist/panels/MapillaryPanel.d.ts +19 -1
  27. package/dist/panels/PanoramaxPanel.d.ts +14 -4
  28. package/dist/panels/PanoramaxWebViewerPanel.d.ts +20 -0
  29. package/dist/panels/mapillaryLookAt.d.ts +41 -0
  30. package/dist/panels/panoramaxDataProvider.d.ts +44 -0
  31. package/dist/panels/panoramaxItem.d.ts +96 -0
  32. package/dist/panels/panoramaxLimitPanning.d.ts +54 -0
  33. package/dist/panels/panoramaxPhotoFromMetadata.d.ts +8 -0
  34. package/dist/panoramax-web-viewer/index.d.ts +1 -0
  35. package/dist/panoramax-web-viewer.js +314 -0
  36. package/dist/photo-details/PhotoDetailsDialog.d.ts +21 -0
  37. package/dist/photo-details/index.d.ts +6 -0
  38. package/dist/photo-details/labels.d.ts +33 -0
  39. package/dist/photo-details.js +235 -0
  40. package/dist/streetImageryClick.d.ts +4 -0
  41. package/dist/viewer-panels/index.d.ts +5 -0
  42. package/dist/viewer-panels.js +3 -0
  43. package/dist/viewpoints/FloatingPhotoViewer.d.ts +73 -0
  44. package/dist/viewpoints/ViewpointLayer.d.ts +17 -0
  45. package/dist/viewpoints/useViewSuggestions.d.ts +23 -0
  46. package/dist/viewpoints/useViewpointSessionStore.d.ts +35 -0
  47. package/dist/viewpoints/viewDirectionLabels.d.ts +4 -0
  48. package/package.json +37 -7
  49. package/dist/MapillaryPanel-QX6NESX7.js +0 -2
  50. package/dist/PanoramaxPanel-J6ANR6LB.js +0 -2
  51. package/dist/chunk-BS6LPDMY.js +0 -143
  52. package/dist/chunk-ZH3TPW4D.js +0 -165
package/README.md CHANGED
@@ -10,8 +10,9 @@ React + MapLibre UI on top of `@osm-editor-kit/street-imagery`:
10
10
  - Map sources and layers for photos, sequences, and viewfields
11
11
  - Click handling and interactive layer ids
12
12
  - TanStack Query hooks to load provider data for the viewport
13
- - Lazy Mapillary and Panoramax viewer panels
13
+ - Lazy viewer panels: Mapillary and Panoramax photos in one viewer (`mapillary-js`)
14
14
  - Helpers for selection, thumbnails, and easing the map to a photo
15
+ - Viewpoints + floating photo viewer: suggested views per direction, history, map layer
15
16
 
16
17
  ## Usage
17
18
 
@@ -39,6 +40,8 @@ const bbox = useMapViewportBbox('main', map)
39
40
  selectedPhoto,
40
41
  photoCircleColor: '#3b82f6',
41
42
  mapFeatureCircleColor: '#94a3b8',
43
+ beforeId: 'road-label', // optional: draw everything below this layer of your style
44
+ minZoom: 10, // optional: below this zoom nothing is requested or drawn
42
45
  }}
43
46
  />
44
47
 
@@ -49,6 +52,178 @@ const hits = queryStreetImageryFeatures(event)
49
52
  onPhotoSelected={setSelection} onEaseMapToPoint={(lng, lat) => map.easeTo({ center: [lng, lat] })} />
50
53
  ```
51
54
 
52
- **Mapillary:** `createStreetImageryConfig({ mapillaryToken })` or `setStreetImageryConfig` at boot (`@osm-editor-kit/street-imagery`). **Panoramax + Vite:** see `app/vite.config.ts` for the consuming-app setup.
55
+ **Before photos are loaded:** where a provider has own vector tiles with its track lines (Mapillary: zoom 6 to 15), MapLibre reads those itself. Same colours and filters; the lines are not clickable. Zoomed far out these tiles are several MB each in dense areas; set `options.minZoom` to skip them.
53
56
 
54
- Also: `useAllProviderPhotos`, `useProviderPhotos` / `useProviderSequences` / `useProviderMapFeatures`, `usePhotoThumbnails`, `resolveSelectedSequence`, `StreetLevelImageryViewCone`, `useViewerBearing` / `useViewerActions`, `MapillaryPanel`, `PanoramaxPanel`.
57
+ **Mapillary:** `createStreetImageryConfig({ mapillaryToken })` or `setStreetImageryConfig` at boot (`@osm-editor-kit/street-imagery`). **Panoramax:** nothing to set up, the Mapillary viewer shows its pictures too (see below).
58
+
59
+ Also: `useAllProviderPhotos`, `useProviderPhotos` / `useProviderSequences` / `useProviderMapFeatures`, `usePhotoThumbnails`, `resolveSelectedSequence`, `StreetLevelImageryViewCone`, `useViewerBearing` / `useViewerActions`. The panels themselves (`MapillaryPanel`, `PanoramaxPanel`) are in `@osm-editor-kit/street-imagery-react/viewer-panels`; `StreetLevelImageryViewer` loads them on demand, so `mapillary-js` is only loaded when a photo is shown.
60
+
61
+ ### Panoramax in the Mapillary viewer
62
+
63
+ `PanoramaxPanel` is a `mapillary-js` viewer with a `PanoramaxDataProvider`, which reads the Panoramax API. One viewer engine for both providers: the same arrows, the same view cone on the map, no second engine to load and no build setup.
64
+
65
+ - A picture opens with its `sd` file (2048 px wide). When you zoom in, the original file is loaded once and the sharp parts are cut from it in the browser.
66
+ - Steps along the sequence work (previous, next, play). The arrows to pictures nearby do not: they need Mapillary's 3D reconstruction.
67
+ - The panel shows creator and licence in a line at the bottom; `hideAttribution` removes it.
68
+ - `PanoramaxDataProvider` is exported from `viewer-panels` for a `mapillary-js` `Viewer` you own: `new Viewer({ container, dataProvider: new PanoramaxDataProvider({ endpoint }), imageId })`.
69
+
70
+ **Panoramax's own viewer** (`@panoramax/web-viewer`) is still there as an option:
71
+
72
+ ```tsx
73
+ import { PanoramaxWebViewerPanel } from '@osm-editor-kit/street-imagery-react/panoramax-web-viewer'
74
+
75
+ <StreetLevelImageryViewer panoramaxPanel={PanoramaxWebViewerPanel} … />
76
+ ```
77
+
78
+ Only then you need `@panoramax/web-viewer` (an optional peer dependency) and its Vite setup: see `vite.config.ts` of [street-level-imagery-provider-overview](https://github.com/osmberlin/street-level-imagery-provider-overview).
79
+
80
+ ## Viewpoints and floating viewer
81
+
82
+ Click → viewpoints → ranked Mapillary photos per view direction → floating viewer with chips and history.
83
+
84
+ ```tsx
85
+ import { viewpointFromPoint, viewpointsFromLine } from '@osm-editor-kit/street-imagery'
86
+ import {
87
+ FloatingPhotoViewer,
88
+ getViewpointSession,
89
+ useViewpoints,
90
+ useViewSuggestions,
91
+ ViewpointLayer,
92
+ VIEWPOINT_DIRECTION_LAYER_ID,
93
+ viewDirectionKeyFromFeatures,
94
+ } from '@osm-editor-kit/street-imagery-react'
95
+
96
+ // On map click (add VIEWPOINT_DIRECTION_LAYER_ID to interactiveLayerIds):
97
+ getViewpointSession().actions.open({ viewpoints: [viewpointFromPoint([lng, lat])] })
98
+ // or for a clicked line: open({ viewpoints: viewpointsFromLine(line, [lng, lat]), line })
99
+
100
+ const viewpoints = useViewpoints()
101
+ const { suggestions } = useViewSuggestions(viewpoints, { maxAgeYears: 2 })
102
+ // <ViewpointLayer viewpoints={viewpoints} suggestions={suggestions} activeDirectionKey={…} zoom={zoom} />
103
+ // <FloatingPhotoViewer suggestions={suggestions} … >{viewer}</FloatingPhotoViewer>
104
+ ```
105
+
106
+ Render `FloatingPhotoViewer` inside a positioned map container. Photos from suggestions open in
107
+ `StreetLevelImageryViewer` with `lookAtBearing={suggestion.direction.bearing}`.
108
+
109
+ **Tailwind:** components use Tailwind classes. Tailwind does not scan `node_modules`, so add to your CSS:
110
+
111
+ ```css
112
+ @source '../node_modules/@osm-editor-kit/street-imagery-react';
113
+ ```
114
+
115
+ ## Look at a place, outline detections
116
+
117
+ ```tsx
118
+ import { JUNCTION_DETECTION_GROUPS, matchesAnyGroup, PLACE_TARGET } from '@osm-editor-kit/street-imagery'
119
+ import {
120
+ StreetLevelImageryViewer,
121
+ useMapillaryImageDetections,
122
+ useMapillaryMapFeatureImages,
123
+ useMapillaryMapFeaturesNear,
124
+ } from '@osm-editor-kit/street-imagery-react'
125
+
126
+ // Turn any Mapillary photo (360° or flat) towards a junction:
127
+ <StreetLevelImageryViewer photo={photo} lookAt={{ lngLat: node, shape: PLACE_TARGET }} … />
128
+
129
+ // Turn to a detected sign or object and outline it. `value` lets the viewer find the image's own
130
+ // detection when Mapillary linked no outline for this image:
131
+ const { data } = useMapillaryMapFeatureImages(featureId)
132
+ <StreetLevelImageryViewer photo={…} lookAt={{ lngLat: data.feature.lngLat, value: data.feature.value }} … />
133
+
134
+ // Features around a point, and only the outlines you care about in the shown image:
135
+ const { data: features } = useMapillaryMapFeaturesNear(node, { radiusMeters: 40 })
136
+ const { data: detections } = useMapillaryImageDetections(photo.photoId, {
137
+ filter: matchesAnyGroup(JUNCTION_DETECTION_GROUPS),
138
+ filterKey: 'junction',
139
+ })
140
+ <StreetLevelImageryViewer photo={photo} outlines={detections?.map((d) => ({ id: d.id, outline: d.outline }))} … />
141
+ ```
142
+
143
+ - Map layers: `filter.mapFeatureValue` limits which signs/objects are drawn: `signGroupFilter(['parking', 'bike'])` for sign groups, or `matchesAnyGroup(…)`.
144
+ - Suggested views: `useViewSuggestions(viewpoints, { sources: [mapillaryPhotoSource, streetViewPhotoSource] })`.
145
+ - `turnMapillaryViewerTo` / `setMapillaryViewerOutlines` (from `@osm-editor-kit/street-imagery-react/viewer-panels`) work on a mapillary-js `Viewer` you own.
146
+
147
+ ## A selected sign: viewer, bar and map highlight
148
+
149
+ Keep the selected sign (`featureId`) and its shown photo in your own state or URL:
150
+
151
+ ```tsx
152
+ const { data, shownImage, firstImage } = useSelectedMapillaryFeature({
153
+ featureId,
154
+ shownPhotoId, // the photo the viewer shows now
155
+ minCapturedAt: fromMs, // optional: open the best photo from this time on
156
+ })
157
+ // Open `firstImage` first: showPhoto(targetImageToPhoto(firstImage))
158
+ <MapillaryFeatureBar data={data} shownImage={shownImage} onShow={(image) => showPhoto(targetImageToPhoto(image))} />
159
+ <StreetLevelImageryViewer lookAt={{ lngLat: data.feature.lngLat, outline: shownImage?.outline, value: data.feature.value }} … />
160
+ // On the map, after StreetLevelImagerySourcesAndLayers: the sign's halo and a line from the camera
161
+ <SelectedMapFeatureLayer data={data} shownImage={shownImage} providers={providers} bbox={bbox} zoom={zoom} />
162
+ ```
163
+
164
+ A click on a sign dot: `queryStreetImageryFeatures(event).find((hit) => hit.kind === 'mapFeature')?.featureId`.
165
+
166
+ ## Date filter with a slider
167
+
168
+ `PhotoDateRangeFilter` is the date filter of iD's photo panel as a controlled component: one slider with two handles on a scale that gives recent years more room. It works on plain `{ from?, to? }` days (`YYYY-MM-DD`), the same `DateRange` the layers take as `filter.date`.
169
+
170
+ ```tsx
171
+ const { photos } = useAllProviderPhotos(providers, bbox, zoom) // no date: all photos in view
172
+
173
+ <PhotoDateRangeFilter
174
+ value={date}
175
+ onChange={setDate} // on release of a handle, not while dragging
176
+ capturedAt={photos.map((photo) => photo.capturedAt)} // marks: where photos are
177
+ yearLines={[1, 2, 3, 4]} // lines with a label; a click shows the last N years
178
+ recommendedMaxAgeYears={2} // this line is red
179
+ markers={[{ date: '2024-04-01', label: 'Survey start' }]} // dashed lines for fixed dates
180
+ dateInputs="collapsed" // exact days: 'collapsed' (default), 'open' or 'none'
181
+ />
182
+ ```
183
+
184
+ A handle at its end means no limit, so the left end also shows photos older than the slider spans (`maxYears`, default 10). The scale itself is in the core package (`dateSliderPosition`, `dateSliderBins`, …) for a host that draws its own chart. The texts are in `messages.dateFilter`.
185
+
186
+ ## Pick a place on the map to open elsewhere
187
+
188
+ A button arms a location opener (see `@osm-editor-kit/street-imagery`), the next map click opens the clicked place in that service and disarms; Escape cancels.
189
+
190
+ ```tsx
191
+ import {
192
+ LocationPickOnMap,
193
+ useArmedLocationOpenerId,
194
+ useLocationPickActions,
195
+ } from '@osm-editor-kit/street-imagery-react'
196
+
197
+ const armed = useArmedLocationOpenerId() // show it: pressed button, crosshair cursor, a hint on the map
198
+ const { toggle, disarm } = useLocationPickActions()
199
+
200
+ {
201
+ getLocationOpeners().map((opener) => (
202
+ <button key={opener.id} aria-pressed={armed === opener.id} onClick={() => toggle(opener.id)}>
203
+ Open in {opener.label}
204
+ </button>
205
+ ))
206
+ }
207
+ ;<Map cursor={armed ? 'crosshair' : undefined}>
208
+ <LocationPickOnMap />
209
+ </Map>
210
+ ```
211
+
212
+ The map's own click handlers still run; skip them while `armed` is set if the click should only open the place. When the place is known already (a selected feature), call `openLocationInNewTab` directly instead.
213
+
214
+ ## Photo details dialog (optional)
215
+
216
+ A modal with everything known about the shown photo: capture, camera, position, source and raw EXIF. It lives in its own entry, so apps that do not import it do not bundle it.
217
+
218
+ ```tsx
219
+ import { FloatingViewerInfoButton } from '@osm-editor-kit/street-imagery-react'
220
+ import { PHOTO_DETAILS_LABELS, PhotoDetailsDialog } from '@osm-editor-kit/street-imagery-react/photo-details'
221
+
222
+ <FloatingPhotoViewer
223
+ titleActions={<FloatingViewerInfoButton label={PHOTO_DETAILS_LABELS.en.open} onClick={() => setOpen(true)} />}
224
+ …
225
+ />
226
+ <PhotoDetailsDialog open={open} photo={viewerPhoto} onClose={() => setOpen(false)} />
227
+ ```
228
+
229
+ `viewerPhoto` is what `onViewerPhoto` of the viewer gives (Mapillary, Panoramax).
@@ -0,0 +1,2 @@
1
+ export { MapillaryPanel } from './chunk-SGIB7AVC.js';
2
+ import './chunk-25UGGXIE.js';
@@ -0,0 +1,2 @@
1
+ export { PanoramaxPanel } from './chunk-XQXYV6SR.js';
2
+ import './chunk-25UGGXIE.js';
@@ -1,9 +1,28 @@
1
- import type { Bbox, NormalizedPhoto, NormalizedSequence } from '@osm-editor-kit/street-imagery';
1
+ import type { NormalizedPhoto, NormalizedSequence } from '@osm-editor-kit/street-imagery';
2
+ /** Lines and photo dots: near black. The shown photo's line is thicker, its marker larger. */
3
+ export declare const BASE_COLOR = "#171717";
4
+ /** The shown photo: fill of its marker and camera pin (black outline), and the line between. */
5
+ export declare const SELECTION_COLOR = "#f97316";
6
+ /** Width of the shown photo's sequence line; other lines are 1.25. */
7
+ export declare const ACTIVE_LINE_WIDTH = 2.5;
2
8
  export type StreetLevelImagerySelectionOverlayProps = {
3
9
  selectedPhoto?: NormalizedPhoto | null;
4
10
  selectedSequence?: NormalizedSequence | null;
11
+ /**
12
+ * Where the viewer says the camera was (Mapillary: the computed position, which the view cone
13
+ * starts at). When it differs from the photo dot, a pin marks it and a line connects both.
14
+ */
15
+ cameraLngLat?: [number, number] | null;
16
+ /** Layer to draw the sequence line below, so photo dots stay on top of it. */
17
+ sequenceBeforeId?: string;
18
+ /** Id of a layer of the host's style to draw the whole overlay below. */
19
+ beforeId?: string;
5
20
  };
6
- export declare const StreetLevelImagerySelectionOverlay: ({ selectedPhoto, selectedSequence, }: StreetLevelImagerySelectionOverlayProps) => import("react").JSX.Element | null;
21
+ /**
22
+ * The shown photo on the map, bottom to top: its sequence line (only passed when the provider's
23
+ * own layers are off; else that layer marks it), a filled marker on its photo dot, and — when the camera position differs from the
24
+ * dot — a dashed connector and a pin at the camera position.
25
+ */
26
+ export declare const StreetLevelImagerySelectionOverlay: ({ selectedPhoto, selectedSequence, cameraLngLat, sequenceBeforeId, beforeId, }: StreetLevelImagerySelectionOverlayProps) => import("react").JSX.Element | null;
7
27
  /** Resolve sequence geometry for highlight when only photo + fetched sequences are available. */
8
28
  export declare const resolveSelectedSequence: (selectedPhoto: NormalizedPhoto | null | undefined, sequences: NormalizedSequence[], sequenceId: string | null | undefined) => NormalizedSequence | null;
9
- export type SequenceHighlightBbox = Bbox | null;
@@ -6,6 +6,11 @@ import type { DataDrivenPropertyValueSpecification } from 'maplibre-gl';
6
6
  export type PhotoFilter = {
7
7
  photoTypes?: PhotoTypeFilter[];
8
8
  date?: DateRange;
9
+ /**
10
+ * Which map features (signs, objects) to draw, by Mapillary value. Use `matchesAnyGroup(...)`
11
+ * for groups like traffic lights or bike signs. Keep the function identity stable.
12
+ */
13
+ mapFeatureValue?: (value: string) => boolean;
9
14
  };
10
15
  export type StreetLevelImagerySourcesAndLayersProps = {
11
16
  providers: ProviderId[];
@@ -15,7 +20,7 @@ export type StreetLevelImagerySourcesAndLayersProps = {
15
20
  options: {
16
21
  config?: StreetImageryConfig;
17
22
  showSequences?: boolean;
18
- /** Always-on heading wedges / 360° disks for every photo. Default true. */
23
+ /** Heading wedges / 360° disks per photo, from zoom 17, capped for dense areas. Default true. */
19
24
  showViewfields?: boolean;
20
25
  showViewCone?: boolean;
21
26
  showSelectionHighlight?: boolean;
@@ -26,8 +31,26 @@ export type StreetLevelImagerySourcesAndLayersProps = {
26
31
  hfov?: number | null;
27
32
  lngLat?: [number, number] | null;
28
33
  } | null;
34
+ /**
35
+ * Style colour of a photo (by type, age …). It colours the view-direction shapes; photo dots
36
+ * and sequence lines are black.
37
+ */
29
38
  photoCircleColor: DataDrivenPropertyValueSpecification<string>;
39
+ /** Colour of the shown photo's view cone. Default: the selection colour (orange). */
40
+ viewConeColor?: DataDrivenPropertyValueSpecification<string>;
41
+ /** Length of the shown photo's view cone, as a multiple of the per-photo shapes. Default 2.5. */
42
+ viewConeScale?: number;
30
43
  mapFeatureCircleColor: DataDrivenPropertyValueSpecification<string>;
44
+ /**
45
+ * Id of a layer of the host's style: all layers are drawn below it (e.g. below road names).
46
+ * The layer must exist when this component mounts. Default: on top of the style.
47
+ */
48
+ beforeId?: string;
49
+ /**
50
+ * Below this map zoom nothing is requested or drawn. Each provider also has its own minimum
51
+ * zooms (photos, lines); the higher one counts. Default: only the providers' own.
52
+ */
53
+ minZoom?: number;
31
54
  };
32
55
  };
33
56
  export declare const StreetLevelImagerySourcesAndLayers: ({ providers, filter, bbox, zoom, options, }: StreetLevelImagerySourcesAndLayersProps) => import("react").JSX.Element;
@@ -1,4 +1,7 @@
1
1
  import type { NormalizedPhoto } from '@osm-editor-kit/street-imagery';
2
+ import type { DataDrivenPropertyValueSpecification } from 'maplibre-gl';
3
+ /** Fill of view-direction shapes: the 360° disks, the flat wedges and the shown photo's cone. */
4
+ export declare const VIEW_SHAPE_FILL_OPACITY = 0.25;
2
5
  export type StreetLevelImageryViewConeProps = {
3
6
  selectedPhoto: NormalizedPhoto;
4
7
  zoom: number;
@@ -7,5 +10,14 @@ export type StreetLevelImageryViewConeProps = {
7
10
  hfov?: number | null;
8
11
  lngLat?: [number, number] | null;
9
12
  } | null;
13
+ /**
14
+ * Fill colour; an expression may read the photo's `isPano` and `capturedAt`, so the cone gets
15
+ * the same colour as the photo's own view-direction shape.
16
+ */
17
+ color?: DataDrivenPropertyValueSpecification<string>;
18
+ /** Cone length as a multiple of the per-photo view-direction shapes. Default 2.5. */
19
+ scale?: number;
20
+ /** Id of a layer of the host's style to draw the cone below. */
21
+ beforeId?: string;
10
22
  };
11
- export declare const StreetLevelImageryViewCone: ({ selectedPhoto, zoom, viewerPov, }: StreetLevelImageryViewConeProps) => import("react").JSX.Element | null;
23
+ export declare const StreetLevelImageryViewCone: ({ selectedPhoto, zoom, viewerPov, color, scale, beforeId, }: StreetLevelImageryViewConeProps) => import("react").JSX.Element | null;
@@ -1,10 +1,32 @@
1
1
  import type { NormalizedPhoto } from '@osm-editor-kit/street-imagery';
2
+ import { type ComponentType } from 'react';
3
+ import type { MapillaryLookAt, MapillaryViewerOutline } from './panels/mapillaryLookAt';
4
+ import type { PanoramaxPanelProps } from './panels/PanoramaxPanel';
2
5
  import type { StreetImageryPhotoSelection } from './types';
3
6
  type StreetLevelImageryViewerProps = {
4
7
  photo: NormalizedPhoto;
5
8
  groupPhotos: NormalizedPhoto[];
6
9
  onPhotoSelected: (selection: StreetImageryPhotoSelection) => void;
7
10
  onEaseMapToPoint: (lng: number, lat: number) => void;
11
+ /** Mapillary, Panoramax: full photo data (creator, licence …) for each image the viewer shows. */
12
+ onViewerPhoto?: (photo: NormalizedPhoto) => void;
13
+ /** Mapillary 360° photos: initial view bearing (e.g. a suggested view direction). */
14
+ lookAtBearing?: number | null;
15
+ /** Mapillary: turn and zoom to a place (sign, traffic light, junction); wins over `lookAtBearing`. */
16
+ lookAt?: MapillaryLookAt | null;
17
+ /** Mapillary: outlines to draw in the shown image. */
18
+ outlines?: MapillaryViewerOutline[];
19
+ /**
20
+ * Hide the viewer's own attribution; the host must then show creator and licence itself, from
21
+ * `onViewerPhoto`.
22
+ */
23
+ hideAttribution?: boolean;
24
+ /**
25
+ * Another panel for Panoramax pictures, e.g. `PanoramaxWebViewerPanel` of the
26
+ * `panoramax-web-viewer` entry (Panoramax's own viewer). Default: the Mapillary viewer shows
27
+ * them too.
28
+ */
29
+ panoramaxPanel?: ComponentType<PanoramaxPanelProps>;
8
30
  };
9
- export declare const StreetLevelImageryViewer: ({ photo, groupPhotos, onPhotoSelected, onEaseMapToPoint, }: StreetLevelImageryViewerProps) => import("react").JSX.Element | null;
31
+ export declare const StreetLevelImageryViewer: ({ photo, groupPhotos, onPhotoSelected, onEaseMapToPoint, onViewerPhoto, lookAtBearing, lookAt, outlines, hideAttribution, panoramaxPanel: PanoramaxPanelOverride, }: StreetLevelImageryViewerProps) => import("react").JSX.Element | null;
10
32
  export {};
@@ -0,0 +1,147 @@
1
+ import { DEFAULT_STREET_IMAGERY_LOCALE } from '@osm-editor-kit/street-imagery';
2
+ import { createContext, use } from 'react';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ // src/i18n/messages.ts
6
+ var en = {
7
+ viewer: {
8
+ regionLabel: "Photo viewer",
9
+ loading: "Loading viewer\u2026",
10
+ backInHistory: "Back in history ([)",
11
+ forwardInHistory: "Forward in history (])",
12
+ minimize: "Minimize",
13
+ close: "Close (Esc)",
14
+ suggestedViews: "Suggested views",
15
+ suggestedViewsHint: "Suggested views: where the photo is taken from, and which way it looks",
16
+ noPhoto: (label) => `${label} (no photo)`,
17
+ noMatchingPhoto: (label) => `${label}: no matching photo`,
18
+ nextPhotoOfView: (label) => `${label} \u2014 click for the next photo`
19
+ },
20
+ unknownDate: "Unknown date",
21
+ dateFilter: {
22
+ allDates: "All dates",
23
+ since: (date) => `Since ${date}`,
24
+ until: (date) => `Until ${date}`,
25
+ between: (from, to) => `${from} \u2013 ${to}`,
26
+ yearsShort: (years) => `${years} y`,
27
+ lastYears: (years) => years === 1 ? "Show the last year" : `Show the last ${years} years`,
28
+ recommendedMaxAge: (years) => `Recommended: photos of the last ${years === 1 ? "year" : `${years} years`}`,
29
+ fromHandle: "Oldest photos to show",
30
+ toHandle: "Newest photos to show",
31
+ exactDates: "Exact dates",
32
+ from: "From",
33
+ to: "To",
34
+ photoCount: (count) => count === 1 ? "1 photo" : `${count.toLocaleString("en")} photos`
35
+ },
36
+ viewpointRole: {
37
+ here: "Here",
38
+ "line-start": "Start",
39
+ "line-end": "End",
40
+ "into-node": "Junction",
41
+ custom: "View"
42
+ },
43
+ compass: ["N", "NE", "E", "SE", "S", "SW", "W", "NW"],
44
+ viewDirection: (role, kind) => {
45
+ switch (kind) {
46
+ case "forward":
47
+ return `${role}, looking along the street`;
48
+ case "back":
49
+ return `${role}, looking back along the street`;
50
+ case "right":
51
+ return `${role}, looking right across the street`;
52
+ case "left":
53
+ return `${role}, looking left across the street`;
54
+ case "into":
55
+ return `${role}, looking into the junction`;
56
+ default:
57
+ return `${role}, looking ${kind}`;
58
+ }
59
+ }
60
+ };
61
+ var COMPASS_DE = { N: "Norden", E: "Osten", S: "S\xFCden", W: "Westen" };
62
+ var de = {
63
+ viewer: {
64
+ regionLabel: "Fotoansicht",
65
+ loading: "Ansicht wird geladen\u2026",
66
+ backInHistory: "Zur\xFCck im Verlauf ([)",
67
+ forwardInHistory: "Vor im Verlauf (])",
68
+ minimize: "Minimieren",
69
+ close: "Schlie\xDFen (Esc)",
70
+ suggestedViews: "Vorgeschlagene Blicke",
71
+ suggestedViewsHint: "Vorgeschlagene Blicke: von wo das Foto aufgenommen ist und wohin es schaut",
72
+ noPhoto: (label) => `${label} (kein Foto)`,
73
+ noMatchingPhoto: (label) => `${label}: kein passendes Foto`,
74
+ nextPhotoOfView: (label) => `${label} \u2014 klicken f\xFCr das n\xE4chste Foto`
75
+ },
76
+ unknownDate: "Datum unbekannt",
77
+ dateFilter: {
78
+ allDates: "Alle Daten",
79
+ since: (date) => `Seit ${date}`,
80
+ until: (date) => `Bis ${date}`,
81
+ between: (from, to) => `${from} \u2013 ${to}`,
82
+ yearsShort: (years) => `${years} J.`,
83
+ lastYears: (years) => years === 1 ? "Das letzte Jahr zeigen" : `Die letzten ${years} Jahre zeigen`,
84
+ recommendedMaxAge: (years) => `Empfohlen: Fotos ${years === 1 ? "des letzten Jahres" : `der letzten ${years} Jahre`}`,
85
+ fromHandle: "\xC4lteste Fotos, die gezeigt werden",
86
+ toHandle: "Neueste Fotos, die gezeigt werden",
87
+ exactDates: "Genaue Daten",
88
+ from: "Von",
89
+ to: "Bis",
90
+ photoCount: (count) => count === 1 ? "1 Foto" : `${count.toLocaleString("de")} Fotos`
91
+ },
92
+ viewpointRole: {
93
+ here: "Hier",
94
+ "line-start": "Anfang",
95
+ "line-end": "Ende",
96
+ "into-node": "Knoten",
97
+ custom: "Blick"
98
+ },
99
+ compass: ["N", "NO", "O", "SO", "S", "SW", "W", "NW"],
100
+ viewDirection: (role, kind) => {
101
+ switch (kind) {
102
+ case "forward":
103
+ return `${role}, Blick entlang der Stra\xDFe`;
104
+ case "back":
105
+ return `${role}, Blick zur\xFCck entlang der Stra\xDFe`;
106
+ case "right":
107
+ return `${role}, Blick nach rechts quer zur Stra\xDFe`;
108
+ case "left":
109
+ return `${role}, Blick nach links quer zur Stra\xDFe`;
110
+ case "into":
111
+ return `${role}, Blick in den Knoten`;
112
+ default:
113
+ return `${role}, Blick nach ${COMPASS_DE[kind] ?? kind}`;
114
+ }
115
+ }
116
+ };
117
+ var STREET_IMAGERY_MESSAGES = {
118
+ en,
119
+ de
120
+ };
121
+ var DEFAULT_I18N = {
122
+ locale: DEFAULT_STREET_IMAGERY_LOCALE,
123
+ messages: STREET_IMAGERY_MESSAGES[DEFAULT_STREET_IMAGERY_LOCALE]
124
+ };
125
+ var I18nContext = createContext(DEFAULT_I18N);
126
+ var mergeMessages = (base, overrides) => overrides ? {
127
+ unknownDate: overrides.unknownDate ?? base.unknownDate,
128
+ dateFilter: { ...base.dateFilter, ...overrides.dateFilter },
129
+ viewer: { ...base.viewer, ...overrides.viewer },
130
+ viewpointRole: { ...base.viewpointRole, ...overrides.viewpointRole },
131
+ compass: overrides.compass?.length === 8 ? overrides.compass : base.compass,
132
+ viewDirection: overrides.viewDirection ?? base.viewDirection
133
+ } : base;
134
+ var StreetImageryLocaleProvider = ({
135
+ locale,
136
+ messages,
137
+ children
138
+ }) => /* @__PURE__ */ jsx(
139
+ I18nContext,
140
+ {
141
+ value: { locale, messages: mergeMessages(STREET_IMAGERY_MESSAGES[locale], messages) },
142
+ children
143
+ }
144
+ );
145
+ var useStreetImageryI18n = () => use(I18nContext);
146
+
147
+ export { STREET_IMAGERY_MESSAGES, StreetImageryLocaleProvider, useStreetImageryI18n };