@ericchen1990/pano-view 0.1.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { ReactNode, ComponentPropsWithoutRef } from 'react';
2
+ import { CSSProperties, ReactNode, ComponentPropsWithoutRef, IframeHTMLAttributes } from 'react';
3
3
  import { Texture, ColorRepresentation, Vector3 } from 'three';
4
4
 
5
5
  declare const MAX_HOTSPOT_PITCH = 90;
@@ -29,9 +29,33 @@ type HotspotDragEvent = HotspotInteractionEvent & {
29
29
  source: "pointer";
30
30
  startPosition: HotspotPosition;
31
31
  };
32
+ /** When a hotspot tooltip is shown. Defaults to `"always"`. */
33
+ type HotspotTooltipTrigger = "always" | "hover" | "click";
34
+ /** Where the tooltip sits relative to the hotspot. Defaults to `"top"`. */
35
+ type HotspotTooltipPlacement = "top" | "bottom" | "left" | "right";
36
+ /** Plain-text and/or image content for a hotspot tooltip. */
37
+ type HotspotTooltipContent = {
38
+ text?: string;
39
+ image?: string;
40
+ imageAlt?: string;
41
+ };
32
42
  type HotspotCommonProps = {
33
43
  id: string;
34
44
  position: HotspotPosition;
45
+ /**
46
+ * Tooltip shown at the hotspot anchor. A string is treated as `{ text }`.
47
+ * Defaults to always visible when content is present.
48
+ */
49
+ tooltip?: string | HotspotTooltipContent;
50
+ /** Defaults to `"always"`. `"hover"` and `"click"` require `interactive`. */
51
+ tooltipTrigger?: HotspotTooltipTrigger;
52
+ /** Defaults to `"top"`. */
53
+ tooltipPlacement?: HotspotTooltipPlacement;
54
+ /**
55
+ * Screen-space gap in CSS pixels between the hotspot edge and the tooltip.
56
+ * Defaults to 12.
57
+ */
58
+ tooltipOffset?: number;
35
59
  /** Angular width in degrees. Defaults to 12. */
36
60
  width?: number;
37
61
  /** Angular height in degrees. Defaults to 8. */
@@ -56,6 +80,11 @@ type HotspotCommonProps = {
56
80
  visible?: boolean;
57
81
  /** Whether the hotspot accepts pointer and keyboard interaction. Defaults to true. */
58
82
  interactive?: boolean;
83
+ /**
84
+ * Canvas cursor while this hotspot is hovered. Defaults to the viewer's
85
+ * `cursors.hotspot` value (`"pointer"`).
86
+ */
87
+ cursor?: CSSProperties["cursor"];
59
88
  draggable?: boolean;
60
89
  /** Required for keyboard-accessible clickable hotspots. */
61
90
  ariaLabel?: string;
@@ -75,7 +104,52 @@ type PanoramaPointerEvent = {
75
104
  clientY: number;
76
105
  };
77
106
 
78
- type PanoViewState = {
107
+ type KeyboardControlAction = "left" | "right" | "up" | "down" | "zoomIn" | "zoomOut" | "previousScene" | "nextScene" | "reset";
108
+ type KeyboardControlKeys = Partial<Record<KeyboardControlAction, string | readonly string[]>>;
109
+ /** Options for keyboard-driven panorama navigation. */
110
+ type KeyboardControlsProps = {
111
+ /** Whether keyboard handling is active. Defaults to true. */
112
+ enabled?: boolean;
113
+ /**
114
+ * Custom key bindings. Each action accepts a key, code, or list of either.
115
+ * Matching is case-insensitive for `event.key` and exact for `event.code`.
116
+ */
117
+ keys?: KeyboardControlKeys;
118
+ /** Yaw/pitch change rate in degrees per second. Defaults to 60. */
119
+ rotateSpeed?: number;
120
+ /** FOV change rate in degrees per second. Defaults to 30. */
121
+ zoomSpeed?: number;
122
+ /** Speed multiplier while Shift is held. Defaults to 3. */
123
+ shiftMultiplier?: number;
124
+ /** Inverts up/down look direction. Defaults to false. */
125
+ invert?: boolean;
126
+ /**
127
+ * Maximum FOV change rate in degrees per second. When omitted, no extra
128
+ * rate cap is applied. Usually supplied by PanoViewer from `controls.fovSpeed`.
129
+ */
130
+ fovSpeed?: number;
131
+ /** Called once when the previous-scene binding is pressed. */
132
+ onPreviousScene?: () => void;
133
+ /** Called once when the next-scene binding is pressed. */
134
+ onNextScene?: () => void;
135
+ };
136
+ /**
137
+ * Returns the scene id `step` positions away from `activeSceneId` in
138
+ * `scenes`, wrapping at both ends. Returns `null` when the list is empty or
139
+ * the active id is missing.
140
+ */
141
+ declare function cycleSceneId(scenes: readonly {
142
+ id: string;
143
+ }[], activeSceneId: string, step: 1 | -1): string | null;
144
+ /**
145
+ * Adds keyboard navigation to the nearest PanoViewer. Enabled by default;
146
+ * render this component only to override properties, bindings, or scene
147
+ * callbacks. Hold movement/zoom keys for continuous motion; scene and reset
148
+ * bindings fire once per key press.
149
+ */
150
+ declare function KeyboardControls({ enabled, keys, rotateSpeed, zoomSpeed, shiftMultiplier, invert, fovSpeed, onPreviousScene, onNextScene, }: KeyboardControlsProps): null;
151
+
152
+ type PanoViewerState = {
79
153
  /** Horizontal look angle in degrees. Positive values look right. */
80
154
  yaw: number;
81
155
  /** Vertical look angle in degrees. Positive values look up. */
@@ -83,13 +157,13 @@ type PanoViewState = {
83
157
  /** Vertical perspective field of view in degrees. */
84
158
  fov: number;
85
159
  };
86
- type SetPanoViewOptions = {
160
+ type SetPanoViewerOptions = {
87
161
  /** Apply the new view immediately instead of preserving current inertia. */
88
162
  immediate?: boolean;
89
163
  };
90
- type PanoViewHandle = {
91
- getView: () => PanoViewState;
92
- setView: (view: Partial<PanoViewState>, options?: SetPanoViewOptions) => void;
164
+ type PanoViewerHandle = {
165
+ getView: () => PanoViewerState;
166
+ setView: (view: Partial<PanoViewerState>, options?: SetPanoViewerOptions) => void;
93
167
  reset: () => void;
94
168
  /** @deprecated Control an AutoRotate component's enabled prop instead. */
95
169
  startAutoRotate: () => void;
@@ -97,16 +171,74 @@ type PanoViewHandle = {
97
171
  stopAutoRotate: () => void;
98
172
  toggleFullscreen: () => Promise<void>;
99
173
  };
174
+ type MouseControlButton = "left" | "middle" | "right";
175
+ /** Options for the default mouse control channel (also MouseControls props). */
176
+ type MouseControlsOptions = {
177
+ /** Whether mouse handling is active. Defaults to true. */
178
+ enabled?: boolean;
179
+ /** Pointer drag multiplier. Defaults to 0.35. */
180
+ rotateSpeed?: number;
181
+ /** Wheel zoom multiplier. Defaults to 0.08. */
182
+ zoomSpeed?: number;
183
+ /** Whether mouse-wheel zoom is enabled. Defaults to true. */
184
+ wheel?: boolean;
185
+ /** Inverts drag direction. Defaults to the all-mode `invert` value. */
186
+ invert?: boolean;
187
+ /** Mouse buttons that may drag the panorama. Defaults to `["left"]`. */
188
+ buttons?: readonly MouseControlButton[];
189
+ };
190
+ /** Options for the default touch control channel (also TouchControls props). */
191
+ type TouchControlsOptions = {
192
+ /** Whether touch handling is active. Defaults to true. */
193
+ enabled?: boolean;
194
+ /** Pointer drag multiplier. Defaults to 0.35. */
195
+ rotateSpeed?: number;
196
+ /** Inverts drag direction. Defaults to the all-mode `invert` value. */
197
+ invert?: boolean;
198
+ /** Whether two-finger pinch zoom is enabled. Defaults to true. */
199
+ pinchZoom?: boolean;
200
+ };
100
201
  type PanoramaControlsOptions = {
202
+ /**
203
+ * Master switch for user view controls. Defaults to true. Setting
204
+ * `controls={false}` on PanoViewer still disables all user input.
205
+ */
206
+ enabled?: boolean;
101
207
  /** Enables drag and zoom inertia. Defaults to true. */
102
208
  inertia?: boolean;
103
- /** @deprecated Render <AutoRotate enabled /> inside PanoView instead. */
209
+ /** @deprecated Render <AutoRotate enabled /> inside PanoViewer instead. */
104
210
  autoRotate?: boolean;
105
211
  /** @deprecated Use AutoRotate's speed prop instead. */
106
212
  autoRotateSpeed?: number;
107
- /** Pointer drag multiplier. Defaults to 0.35. */
213
+ /**
214
+ * Inverts drag/pan direction for mouse and touch. Defaults to false.
215
+ * Per-channel `invert` on MouseControls / TouchControls overrides this.
216
+ */
217
+ invert?: boolean;
218
+ /**
219
+ * Allows pitch and FOV to briefly overshoot hard limits while dragging,
220
+ * then spring back on release. Defaults to false.
221
+ */
222
+ bouncingLimits?: boolean;
223
+ /**
224
+ * Maximum FOV change rate in degrees per second for wheel and keyboard
225
+ * zoom. When omitted, no extra rate cap is applied.
226
+ */
227
+ fovSpeed?: number;
228
+ /**
229
+ * Relative factor for stopping inertia. Lower values fade out more
230
+ * smoothly. Defaults to 0.01.
231
+ */
232
+ frictionStop?: number;
233
+ /**
234
+ * Default pointer drag multiplier for mouse and touch. Defaults to 0.35.
235
+ * Prefer `controls.mouse` / `controls.touch` for per-channel overrides.
236
+ */
108
237
  rotateSpeed?: number;
109
- /** Wheel zoom multiplier. Defaults to 0.08. */
238
+ /**
239
+ * Default wheel zoom multiplier for mouse. Defaults to 0.08.
240
+ * Prefer `controls.mouse.zoomSpeed` for overrides.
241
+ */
110
242
  zoomSpeed?: number;
111
243
  /**
112
244
  * Rotation target-following speed in seconds^-1. Defaults to 14; use 0 for
@@ -118,36 +250,228 @@ type PanoramaControlsOptions = {
118
250
  * immediate response. Must be a non-negative finite number.
119
251
  */
120
252
  zoomDamping?: number;
121
- /** Enables focusable keyboard controls. Defaults to true. */
122
- keyboard?: boolean;
253
+ /**
254
+ * Mouse channel. `true` / omit mounts defaults; `false` disables the
255
+ * default instance; an object merges with defaults and supports `enabled`.
256
+ * Rendering `<MouseControls />` as a child also replaces the default.
257
+ */
258
+ mouse?: boolean | MouseControlsOptions;
259
+ /**
260
+ * Touch channel. Same shape as `mouse`.
261
+ */
262
+ touch?: boolean | TouchControlsOptions;
263
+ /**
264
+ * Keyboard channel. Same shape as `mouse`. Rendering `<KeyboardControls />`
265
+ * as a child replaces the default (no need to set this to false).
266
+ */
267
+ keyboard?: boolean | KeyboardControlsProps;
123
268
  };
124
269
 
125
- type PanoViewProps = Omit<ComponentPropsWithoutRef<"div">, "children" | "onChange"> & {
270
+ /** Lowest allowed `appearance.opacity` (background only). */
271
+ declare const MIN_PANO_CONTEXT_MENU_BACKGROUND_OPACITY = 0.4;
272
+ type PanoContextMenuSelectContext = {
273
+ position: PanoramaPointerEvent["position"];
274
+ view: PanoViewerState;
275
+ nativeEvent: MouseEvent | PointerEvent;
276
+ close: () => void;
277
+ };
278
+ type PanoContextMenuActionItem = {
279
+ type?: "item";
280
+ id: string;
281
+ label: string;
282
+ /** React icon node (inline SVG, icon library component, emoji, etc.). */
283
+ icon?: ReactNode;
284
+ /** Image URL; ignored when `icon` is set. */
285
+ image?: string;
286
+ imageAlt?: string;
287
+ disabled?: boolean;
288
+ hidden?: boolean;
289
+ className?: string;
290
+ style?: CSSProperties;
291
+ onSelect: (context: PanoContextMenuSelectContext) => void;
292
+ };
293
+ type PanoContextMenuSeparatorItem = {
294
+ type: "separator";
295
+ id?: string;
296
+ className?: string;
297
+ style?: CSSProperties;
298
+ };
299
+ type PanoContextMenuItem = PanoContextMenuActionItem | PanoContextMenuSeparatorItem;
300
+ /** Built-in menu entries hosts can reuse without reimplementing behavior. */
301
+ type PanoContextMenuPresetId = "resetView" | "fullscreen" | "separator";
302
+ /**
303
+ * Reference a built-in preset, optionally overriding presentation fields.
304
+ * Action wiring (reset / fullscreen toggle and enter/exit label) stays built-in.
305
+ */
306
+ type PanoContextMenuPresetRef = {
307
+ preset: PanoContextMenuPresetId;
308
+ id?: string;
309
+ label?: string;
310
+ className?: string;
311
+ style?: CSSProperties;
312
+ disabled?: boolean;
313
+ hidden?: boolean;
314
+ };
315
+ /** A custom action item, a preset id string, or a preset ref with overrides. */
316
+ type PanoContextMenuEntry = PanoContextMenuActionItem | PanoContextMenuPresetId | PanoContextMenuPresetRef;
317
+ type PanoContextMenuAppearance = {
318
+ background?: string;
319
+ color?: string;
320
+ border?: string;
321
+ borderRadius?: number | string;
322
+ shadow?: string;
323
+ /**
324
+ * Background-only opacity from {@link MIN_PANO_CONTEXT_MENU_BACKGROUND_OPACITY}
325
+ * to 1. Defaults to 1. Text and icons stay fully opaque.
326
+ */
327
+ opacity?: number;
328
+ fontSize?: number | string;
329
+ minWidth?: number | string;
330
+ padding?: number | string;
331
+ iconSize?: number;
332
+ itemPadding?: string;
333
+ itemHoverBackground?: string;
334
+ itemDisabledColor?: string;
335
+ separatorColor?: string;
336
+ separatorMargin?: string;
337
+ };
338
+ type PanoContextMenuRenderProps = {
339
+ event: PanoramaPointerEvent;
340
+ view: PanoViewerState;
341
+ close: () => void;
342
+ };
343
+ type PanoContextMenuProps = {
344
+ /**
345
+ * Menu entries. May mix concrete items with built-in presets
346
+ * (`"resetView"`, `"fullscreen"`, `"separator"`). When omitted, the
347
+ * default Reset view / Fullscreen list is used (see also `prepend` /
348
+ * `append`).
349
+ */
350
+ items?: readonly PanoContextMenuEntry[];
351
+ /**
352
+ * Entries placed before the default menu when `items` is omitted.
353
+ * Ignored when `items` is provided.
354
+ */
355
+ prepend?: readonly PanoContextMenuEntry[];
356
+ /**
357
+ * Entries placed after the default menu when `items` is omitted.
358
+ * Ignored when `items` is provided.
359
+ */
360
+ append?: readonly PanoContextMenuEntry[];
361
+ appearance?: PanoContextMenuAppearance;
362
+ className?: string;
363
+ style?: CSSProperties;
364
+ itemClassName?: string;
365
+ separatorClassName?: string;
366
+ /**
367
+ * Fully custom menu content. When provided, takes precedence over `items`.
368
+ * Opening, closing, and positioning remain handled by PanoContextMenu.
369
+ */
370
+ children?: (props: PanoContextMenuRenderProps) => ReactNode;
371
+ };
372
+ /**
373
+ * Custom panorama context menu. Must render inside PanoViewer. Prefer
374
+ * PanoViewer's `contextMenu` prop for the default menu; use this component
375
+ * when replacing the default instance (`contextMenu={false}`).
376
+ */
377
+ declare function PanoContextMenu({ items, prepend, append, appearance, className, style, itemClassName, separatorClassName, children, }: PanoContextMenuProps): null;
378
+ type PanoContextMenuPresetActions = {
379
+ reset: () => void;
380
+ toggleFullscreen: () => void;
381
+ /** When true, the fullscreen preset shows Exit fullscreen. */
382
+ isFullscreen?: boolean;
383
+ };
384
+ type PanoContextMenuPresets = {
385
+ resetView: PanoContextMenuActionItem;
386
+ fullscreen: PanoContextMenuActionItem;
387
+ separator: (id?: string) => PanoContextMenuSeparatorItem;
388
+ /** Default menu: Reset view, separator, Enter/Exit fullscreen. */
389
+ defaults: PanoContextMenuItem[];
390
+ };
391
+ /**
392
+ * Builds reusable built-in context-menu items. Prefer preset id strings
393
+ * (`"resetView"`, `"fullscreen"`) in `items` / `append` / `prepend` when
394
+ * configuring `PanoViewer`; use this helper when assembling items manually.
395
+ */
396
+ declare function createPanoContextMenuPresets(actions: PanoContextMenuPresetActions): PanoContextMenuPresets;
397
+ /** Alias for `createPanoContextMenuPresets(actions).defaults`. */
398
+ declare function createDefaultPanoContextMenuItems(actions: PanoContextMenuPresetActions): PanoContextMenuItem[];
399
+ /**
400
+ * Expands preset ids / refs into concrete menu items using the given presets.
401
+ */
402
+ declare function resolvePanoContextMenuEntries(entries: readonly PanoContextMenuEntry[], presets: PanoContextMenuPresets): PanoContextMenuItem[];
403
+ /**
404
+ * Resolves `items`, or `prepend` + defaults + `append` when `items` is omitted.
405
+ */
406
+ declare function composePanoContextMenuItems(props: Pick<PanoContextMenuProps, "items" | "prepend" | "append">, presets: PanoContextMenuPresets): PanoContextMenuItem[];
407
+
408
+ /** A CSS `cursor` value applied to the panorama canvas. */
409
+ type PanoCursor = NonNullable<CSSProperties["cursor"]>;
410
+ /** Canvas cursor values for viewer idle, drag, and hotspot interaction. */
411
+ type PanoCursors = {
412
+ /** Idle canvas cursor. Defaults to `"grab"`. */
413
+ default?: PanoCursor;
414
+ /** Cursor while dragging the panorama with the mouse. Defaults to `"grabbing"`. */
415
+ dragging?: PanoCursor;
416
+ /** Cursor while hovering an interactive hotspot. Defaults to `"pointer"`. */
417
+ hotspot?: PanoCursor;
418
+ /** Cursor while dragging a hotspot. Defaults to `"move"`. */
419
+ hotspotDragging?: PanoCursor;
420
+ };
421
+ declare const DEFAULT_PANO_CURSORS: Required<PanoCursors>;
422
+
423
+ type PanoViewerProps = Omit<ComponentPropsWithoutRef<"div">, "children" | "onChange" | "contextMenu"> & {
126
424
  children?: ReactNode;
127
- initialView?: Partial<PanoViewState>;
425
+ initialView?: Partial<PanoViewerState>;
128
426
  minFov?: number;
129
427
  maxFov?: number;
130
428
  controls?: boolean | PanoramaControlsOptions;
131
- onViewChange?: (view: PanoViewState) => void;
429
+ /**
430
+ * Canvas cursor. `true` / omit uses grab / grabbing / pointer / move;
431
+ * `false` leaves the canvas cursor unchanged; an object merges with the
432
+ * defaults (`default`, `dragging`, `hotspot`, `hotspotDragging`).
433
+ */
434
+ cursors?: boolean | PanoCursors;
435
+ /**
436
+ * Default context menu. `true` / omit mounts Reset view + Fullscreen;
437
+ * `false` skips the default instance; an object merges appearance and
438
+ * may use `items` (full replace, supports preset ids), or `prepend` /
439
+ * `append` to keep the defaults and add entries.
440
+ */
441
+ contextMenu?: boolean | PanoContextMenuProps;
442
+ onViewChange?: (view: PanoViewerState) => void;
132
443
  onPanoramaClick?: (event: PanoramaPointerEvent) => void;
133
444
  onPanoramaDoubleClick?: (event: PanoramaPointerEvent) => void;
134
445
  onPanoramaPointerMove?: (event: PanoramaPointerEvent) => void;
135
446
  /** Canvas pixel ratio. Defaults to a capped range of 1–2. */
136
447
  dpr?: number | [number, number];
137
448
  };
138
- declare const PanoView: react.ForwardRefExoticComponent<Omit<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "children" | "onChange"> & {
449
+ declare const PanoViewer: react.ForwardRefExoticComponent<Omit<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "children" | "contextMenu" | "onChange"> & {
139
450
  children?: ReactNode;
140
- initialView?: Partial<PanoViewState>;
451
+ initialView?: Partial<PanoViewerState>;
141
452
  minFov?: number;
142
453
  maxFov?: number;
143
454
  controls?: boolean | PanoramaControlsOptions;
144
- onViewChange?: (view: PanoViewState) => void;
455
+ /**
456
+ * Canvas cursor. `true` / omit uses grab / grabbing / pointer / move;
457
+ * `false` leaves the canvas cursor unchanged; an object merges with the
458
+ * defaults (`default`, `dragging`, `hotspot`, `hotspotDragging`).
459
+ */
460
+ cursors?: boolean | PanoCursors;
461
+ /**
462
+ * Default context menu. `true` / omit mounts Reset view + Fullscreen;
463
+ * `false` skips the default instance; an object merges appearance and
464
+ * may use `items` (full replace, supports preset ids), or `prepend` /
465
+ * `append` to keep the defaults and add entries.
466
+ */
467
+ contextMenu?: boolean | PanoContextMenuProps;
468
+ onViewChange?: (view: PanoViewerState) => void;
145
469
  onPanoramaClick?: (event: PanoramaPointerEvent) => void;
146
470
  onPanoramaDoubleClick?: (event: PanoramaPointerEvent) => void;
147
471
  onPanoramaPointerMove?: (event: PanoramaPointerEvent) => void;
148
472
  /** Canvas pixel ratio. Defaults to a capped range of 1–2. */
149
473
  dpr?: number | [number, number];
150
- } & react.RefAttributes<PanoViewHandle>>;
474
+ } & react.RefAttributes<PanoViewerHandle>>;
151
475
 
152
476
  /** Options for automatic horizontal panorama rotation. */
153
477
  type AutoRotateProps = {
@@ -164,11 +488,110 @@ type AutoRotateProps = {
164
488
  startDelay?: number;
165
489
  };
166
490
  /**
167
- * Adds automatic rotation to the nearest PanoView. Render one instance as a
168
- * child of PanoView, alongside its panorama source.
491
+ * Adds automatic rotation to the nearest PanoViewer. Render one instance as a
492
+ * child of PanoViewer, alongside its panorama source.
169
493
  */
170
494
  declare function AutoRotate({ enabled, speed, acceleration, startDelay, }: AutoRotateProps): null;
171
495
 
496
+ type ViewInteractionSource = "mouse" | "touch" | "keyboard";
497
+ type PanoWheelEvent = {
498
+ /** Signed wheel delta (same sign convention as WheelEvent.deltaY). */
499
+ delta: number;
500
+ nativeEvent: WheelEvent;
501
+ };
502
+ type PanoResizeEvent = {
503
+ width: number;
504
+ height: number;
505
+ };
506
+ type ViewInteractionEvent = {
507
+ source: ViewInteractionSource;
508
+ };
509
+ type PanoEventMap = {
510
+ viewchange: PanoViewerState;
511
+ viewsettled: PanoViewerState;
512
+ viewinteractionstart: ViewInteractionEvent;
513
+ viewinteractionend: ViewInteractionEvent;
514
+ click: PanoramaPointerEvent;
515
+ doubleclick: PanoramaPointerEvent;
516
+ pointerdown: PanoramaPointerEvent;
517
+ pointerup: PanoramaPointerEvent;
518
+ pointermove: PanoramaPointerEvent;
519
+ contextmenu: PanoramaPointerEvent;
520
+ wheel: PanoWheelEvent;
521
+ idle: undefined;
522
+ idleend: undefined;
523
+ enterfullscreen: undefined;
524
+ exitfullscreen: undefined;
525
+ resize: PanoResizeEvent;
526
+ autorotatestart: undefined;
527
+ autorotatestop: undefined;
528
+ autorotateoneround: undefined;
529
+ };
530
+ type PanoEventType = keyof PanoEventMap;
531
+ type PanoEventListener<T extends PanoEventType> = (payload: PanoEventMap[T]) => void;
532
+ type PanoEventBus = {
533
+ subscribe: <T extends PanoEventType>(type: T, listener: PanoEventListener<T>) => () => void;
534
+ emit: <T extends PanoEventType>(type: T, payload: PanoEventMap[T]) => void;
535
+ };
536
+
537
+ type PanoEventsProps = {
538
+ /**
539
+ * Milliseconds without user interaction before `onIdle`. Defaults to 2000.
540
+ * Each PanoEvents instance tracks idle independently.
541
+ */
542
+ idleTime?: number;
543
+ onViewChange?: (view: PanoViewerState) => void;
544
+ onViewSettled?: (view: PanoViewerState) => void;
545
+ onViewInteractionStart?: (event: ViewInteractionEvent) => void;
546
+ onViewInteractionEnd?: (event: ViewInteractionEvent) => void;
547
+ onClick?: (event: PanoramaPointerEvent) => void;
548
+ onDoubleClick?: (event: PanoramaPointerEvent) => void;
549
+ onPointerDown?: (event: PanoramaPointerEvent) => void;
550
+ onPointerUp?: (event: PanoramaPointerEvent) => void;
551
+ onPointerMove?: (event: PanoramaPointerEvent) => void;
552
+ onContextMenu?: (event: PanoramaPointerEvent) => void;
553
+ onWheel?: (event: PanoWheelEvent) => void;
554
+ onIdle?: () => void;
555
+ onIdleEnd?: () => void;
556
+ onEnterFullscreen?: () => void;
557
+ onExitFullscreen?: () => void;
558
+ onResize?: (event: PanoResizeEvent) => void;
559
+ onAutoRotateStart?: () => void;
560
+ onAutoRotateStop?: () => void;
561
+ onAutoRotateOneRound?: () => void;
562
+ };
563
+ /**
564
+ * Subscribes to viewer-level panorama events. Must run inside PanoViewer.
565
+ * Prefer the {@link PanoEvents} component for declarative usage.
566
+ */
567
+ declare function usePanoEvents({ idleTime, onViewChange, onViewSettled, onViewInteractionStart, onViewInteractionEnd, onClick, onDoubleClick, onPointerDown, onPointerUp, onPointerMove, onContextMenu, onWheel, onIdle, onIdleEnd, onEnterFullscreen, onExitFullscreen, onResize, onAutoRotateStart, onAutoRotateStop, onAutoRotateOneRound, }: PanoEventsProps): void;
568
+ /**
569
+ * Declarative viewer-level event listeners for the nearest PanoViewer.
570
+ * Multiple instances may coexist; each tracks its own idle timer.
571
+ */
572
+ declare function PanoEvents(props: PanoEventsProps): null;
573
+
574
+ type MouseControlsProps = MouseControlsOptions & {
575
+ /**
576
+ * Maximum FOV change rate in degrees per second for wheel zoom. When
577
+ * omitted, no extra rate cap is applied. Usually supplied by PanoViewer from
578
+ * `controls.fovSpeed`.
579
+ */
580
+ fovSpeed?: number;
581
+ };
582
+ /**
583
+ * Adds mouse (and pen) drag / wheel navigation to the nearest PanoViewer.
584
+ * Enabled by default; render this component only to override properties.
585
+ */
586
+ declare function MouseControls({ enabled, rotateSpeed, zoomSpeed, wheel, invert, buttons, fovSpeed, }: MouseControlsProps): null;
587
+
588
+ type TouchControlsProps = TouchControlsOptions;
589
+ /**
590
+ * Adds touch drag and pinch-zoom navigation to the nearest PanoViewer.
591
+ * Enabled by default; render this component only to override properties.
592
+ */
593
+ declare function TouchControls({ enabled, rotateSpeed, invert, pinchZoom, }: TouchControlsProps): null;
594
+
172
595
  type SphereProps = {
173
596
  src: string;
174
597
  /** Horizontal image offset in degrees. */
@@ -245,40 +668,40 @@ type TileProps = {
245
668
  onLevelChange?: (level: number) => void;
246
669
  };
247
670
 
248
- type PanoramaTransitionPreset = "none" | "crossfade" | "zoom" | "blackout" | "whiteFlash" | "slideRightToLeft" | "slideTopToBottom" | "slideDiagonal" | "circleOpen" | "verticalOpen" | "horizontalOpen" | "ellipticZoomOpen";
249
- type PanoramaTransition = PanoramaTransitionPreset | {
250
- preset: PanoramaTransitionPreset;
671
+ type SceneTransitionPreset = "none" | "crossfade" | "zoom" | "blackout" | "whiteFlash" | "slideRightToLeft" | "slideTopToBottom" | "slideDiagonal" | "circleOpen" | "verticalOpen" | "horizontalOpen" | "ellipticZoomOpen";
672
+ type SceneTransition = SceneTransitionPreset | {
673
+ preset: SceneTransitionPreset;
251
674
  /** Overrides the KRpano-compatible default duration in seconds. */
252
675
  duration?: number;
253
676
  };
254
- type SpherePanoramaScene = {
677
+ type SphereScene = {
255
678
  id: string;
256
679
  type: "sphere";
257
680
  src: string;
258
681
  yawOffset?: number;
259
682
  };
260
- type TilePanoramaScene = Omit<TileProps, "loadMode" | "visible" | "onReady" | "onPreviewError" | "onLoadProgress" | "onTileError" | "onLevelChange"> & {
683
+ type TileScene = Omit<TileProps, "loadMode" | "visible" | "onReady" | "onPreviewError" | "onLoadProgress" | "onTileError" | "onLevelChange"> & {
261
684
  id: string;
262
685
  type: "tile";
263
686
  };
264
- type PanoramaScene = SpherePanoramaScene | TilePanoramaScene;
265
- type PanoramaTransitionEndEvent = {
687
+ type Scene = SphereScene | TileScene;
688
+ type SceneTransitionEndEvent = {
266
689
  previousSceneId: string;
267
690
  sceneId: string;
268
- preset: PanoramaTransitionPreset;
691
+ preset: SceneTransitionPreset;
269
692
  };
270
- type PanoramaTransitionErrorEvent = {
693
+ type SceneTransitionErrorEvent = {
271
694
  sceneId: string;
272
695
  error: unknown;
273
696
  };
274
- type PanoramaScenesProps = {
275
- scenes: readonly PanoramaScene[];
697
+ type ScenesProps = {
698
+ scenes: readonly Scene[];
276
699
  activeSceneId: string;
277
- transition?: PanoramaTransition;
700
+ transition?: SceneTransition;
278
701
  /** Rendered only after a scene has finished transitioning in. */
279
- renderHotspots?: (scene: PanoramaScene) => ReactNode;
280
- onTransitionEnd?: (event: PanoramaTransitionEndEvent) => void;
281
- onTransitionError?: (event: PanoramaTransitionErrorEvent) => void;
702
+ renderHotspots?: (scene: Scene) => ReactNode;
703
+ onTransitionEnd?: (event: SceneTransitionEndEvent) => void;
704
+ onTransitionError?: (event: SceneTransitionErrorEvent) => void;
282
705
  /** Viewer-wide budget shared by every tile scene. Defaults to 128 MiB. */
283
706
  maxTextureMemoryMb?: number;
284
707
  /** Viewer-wide tile request limit. Defaults to 4. */
@@ -286,7 +709,7 @@ type PanoramaScenesProps = {
286
709
  /** Maximum physical-pixel area of the outgoing GPU snapshot. */
287
710
  snapshotMaxPixels?: number;
288
711
  };
289
- declare function PanoramaScenes({ maxTextureMemoryMb, maxConcurrentTileLoads, ...props }: PanoramaScenesProps): react.JSX.Element;
712
+ declare function Scenes({ maxTextureMemoryMb, maxConcurrentTileLoads, ...props }: ScenesProps): react.JSX.Element;
290
713
 
291
714
  type ImageHotspotProps = HotspotCommonProps & {
292
715
  src: string;
@@ -361,8 +784,21 @@ type GraphicPaint = {
361
784
  type CircleGraphic = GraphicPaint & {
362
785
  kind: "circle";
363
786
  };
787
+ type TriangleGraphic = GraphicPaint & {
788
+ kind: "triangle";
789
+ };
790
+ type DiamondGraphic = GraphicPaint & {
791
+ kind: "diamond";
792
+ };
793
+ type StarGraphic = GraphicPaint & {
794
+ kind: "star";
795
+ };
796
+ type ArrowGraphic = GraphicPaint & {
797
+ kind: "arrow";
798
+ };
364
799
  type RectangleGraphic = GraphicPaint & {
365
800
  kind: "rectangle";
801
+ /** Relative radius from 0 (square corners) to 0.5 (maximum rounded corners). */
366
802
  cornerRadius?: number;
367
803
  };
368
804
  type RingGraphic = GraphicPaint & {
@@ -378,7 +814,7 @@ type SvgPathGraphic = GraphicPaint & {
378
814
  path: string;
379
815
  viewBox: [x: number, y: number, width: number, height: number];
380
816
  };
381
- type GraphicDefinition = CircleGraphic | RectangleGraphic | RingGraphic | SvgGraphic | SvgPathGraphic;
817
+ type GraphicDefinition = CircleGraphic | TriangleGraphic | DiamondGraphic | StarGraphic | ArrowGraphic | RectangleGraphic | RingGraphic | SvgGraphic | SvgPathGraphic;
382
818
  type GraphicHotspotProps = HotspotCommonProps & {
383
819
  graphic: GraphicDefinition;
384
820
  onLoad?: (texture: Texture) => void;
@@ -444,6 +880,59 @@ type VideoHotspotProps = HotspotCommonProps & {
444
880
  };
445
881
  declare function VideoHotspot({ id, src, playing, poster, loop, muted, volume, playsInline, preload, crossOrigin, width, height, opacity, onPlaybackStateChange, onPlaybackError, onEnded, onError, ...anchorProps }: VideoHotspotProps): react.JSX.Element;
446
882
 
883
+ type TextHotspotAlign = "left" | "center" | "right";
884
+ type TextHotspotVerticalAlign = "top" | "middle" | "bottom";
885
+ type TextHotspotWhiteSpace = "normal" | "nowrap";
886
+ type TextHotspotFontStyle = "normal" | "italic";
887
+ /** Serializable typography and panel paint for a text hotspot. */
888
+ type TextHotspotStyle = {
889
+ fontFamily?: string;
890
+ /** Fraction of the texture height. Defaults to 0.18. */
891
+ fontSize?: number;
892
+ fontWeight?: number | string;
893
+ fontStyle?: TextHotspotFontStyle;
894
+ color?: string;
895
+ /** CSS color. An empty string skips the panel fill. */
896
+ background?: string;
897
+ backgroundOpacity?: number;
898
+ /** Fraction of the texture's shorter side. */
899
+ padding?: number;
900
+ align?: TextHotspotAlign;
901
+ verticalAlign?: TextHotspotVerticalAlign;
902
+ lineHeight?: number;
903
+ whiteSpace?: TextHotspotWhiteSpace;
904
+ /** Fraction of the texture's shorter side, from 0 to 0.5. */
905
+ borderRadius?: number;
906
+ stroke?: string;
907
+ strokeWidth?: number;
908
+ };
909
+ type TextHotspotProps = HotspotCommonProps & TextHotspotStyle & {
910
+ text: string;
911
+ onLoad?: (texture: Texture) => void;
912
+ onError?: (error: unknown) => void;
913
+ };
914
+ declare function TextHotspot({ text, width, height, opacity, fontFamily, fontSize, fontWeight, fontStyle, color, background, backgroundOpacity, padding, align, verticalAlign, lineHeight, whiteSpace, borderRadius, stroke, strokeWidth, onLoad, onError, ...anchorProps }: TextHotspotProps): react.JSX.Element;
915
+
916
+ type IframePointerPolicy = "hotspot" | "content";
917
+ type IframeHotspotProps = HotspotCommonProps & {
918
+ src: string;
919
+ /** Accessible iframe title. Falls back to ariaLabel. */
920
+ title?: string;
921
+ sandbox?: string;
922
+ allow?: string;
923
+ referrerPolicy?: IframeHTMLAttributes<HTMLIFrameElement>["referrerPolicy"];
924
+ loading?: "eager" | "lazy";
925
+ /**
926
+ * `hotspot` lets panorama pointer events hit the WebGL plane.
927
+ * `content` makes the embedded page interactive.
928
+ */
929
+ pointerPolicy?: IframePointerPolicy;
930
+ background?: string;
931
+ onLoad?: () => void;
932
+ onError?: (error: unknown) => void;
933
+ };
934
+ declare function IframeHotspot({ src, title, sandbox, allow, referrerPolicy, loading, pointerPolicy, background, opacity, width, height, onLoad, onError, ...anchorProps }: IframeHotspotProps): react.JSX.Element;
935
+
447
936
  declare function Tile({ baseUrl, multires, previewUrl, previewFaceOrder, urlTemplate, resolveTileUrl, maxTextureMemoryMb, maxConcurrentLoads, retryCount, loadMode, visible, onReady, onPreviewError, onLoadProgress, onTileError, onLevelChange, }: TileProps): react.JSX.Element;
448
937
 
449
938
  declare function normalizePanoYaw(yaw: number): number;
@@ -452,6 +941,8 @@ declare function normalizePanoPosition(position: HotspotPosition): HotspotPositi
452
941
  declare function panoPositionToVector3(position: HotspotPosition, radius?: number): Vector3;
453
942
  declare function vector3ToPanoPosition(vector: Pick<Vector3, "x" | "y" | "z">): HotspotPosition;
454
943
 
944
+ declare const DEFAULT_HOTSPOT_TOOLTIP_OFFSET = 12;
945
+
455
946
  /** Shared serializable fields for every saved hotspot definition. */
456
947
  type HotspotDefinitionBase = {
457
948
  id: string;
@@ -459,7 +950,13 @@ type HotspotDefinitionBase = {
459
950
  label?: string;
460
951
  visible?: boolean;
461
952
  interactive?: boolean;
953
+ /** Canvas cursor while this hotspot is hovered. */
954
+ cursor?: CSSProperties["cursor"];
462
955
  renderOrder?: number;
956
+ tooltip?: string | HotspotTooltipContent;
957
+ tooltipTrigger?: HotspotTooltipTrigger;
958
+ tooltipPlacement?: HotspotTooltipPlacement;
959
+ tooltipOffset?: number;
463
960
  };
464
961
  /** Shared serializable fields for a hotspot anchored at one yaw/pitch point. */
465
962
  type PointHotspotDefinitionBase = HotspotDefinitionBase & {
@@ -503,6 +1000,21 @@ type VideoHotspotDefinition = PointHotspotDefinitionBase & {
503
1000
  preload?: "none" | "metadata" | "auto";
504
1001
  crossOrigin?: "" | "anonymous" | "use-credentials";
505
1002
  };
1003
+ type TextHotspotDefinition = PointHotspotDefinitionBase & TextHotspotStyle & {
1004
+ type: "text";
1005
+ text: string;
1006
+ };
1007
+ type IframeHotspotDefinition = PointHotspotDefinitionBase & {
1008
+ type: "iframe";
1009
+ src: string;
1010
+ title?: string;
1011
+ sandbox?: string;
1012
+ allow?: string;
1013
+ referrerPolicy?: string;
1014
+ loading?: "eager" | "lazy";
1015
+ pointerPolicy?: IframePointerPolicy;
1016
+ background?: string;
1017
+ };
506
1018
  type PolygonHotspotDefinition = HotspotDefinitionBase & {
507
1019
  type: "polygon";
508
1020
  vertices: HotspotPosition[];
@@ -512,7 +1024,7 @@ type PolygonHotspotDefinition = HotspotDefinitionBase & {
512
1024
  strokeWidth?: number;
513
1025
  strokeOpacity?: number;
514
1026
  };
515
- /** An open path. This extends the original five hotspot categories. */
1027
+ /** An open path. This extends the original point and polygon hotspot categories. */
516
1028
  type PolylineHotspotDefinition = HotspotDefinitionBase & {
517
1029
  type: "polyline";
518
1030
  vertices: HotspotPosition[];
@@ -520,8 +1032,8 @@ type PolylineHotspotDefinition = HotspotDefinitionBase & {
520
1032
  strokeWidth?: number;
521
1033
  strokeOpacity?: number;
522
1034
  };
523
- type PointHotspotDefinition = ImageHotspotDefinition | GraphicHotspotDefinition | SequenceHotspotDefinition | VideoHotspotDefinition;
1035
+ type PointHotspotDefinition = ImageHotspotDefinition | GraphicHotspotDefinition | SequenceHotspotDefinition | VideoHotspotDefinition | TextHotspotDefinition | IframeHotspotDefinition;
524
1036
  /** A serializable, discriminated hotspot collection item. */
525
1037
  type HotspotDefinition = PointHotspotDefinition | PolygonHotspotDefinition | PolylineHotspotDefinition;
526
1038
 
527
- export { AutoRotate, type AutoRotateProps, type CircleGraphic, type CubeFaceCode, type GraphicDefinition, GraphicHotspot, type GraphicHotspotDefinition, type GraphicHotspotProps, type HotspotCommonProps, type HotspotDefinition, type HotspotDefinitionBase, type HotspotDragEvent, type HotspotInputSource, type HotspotInteractionEvent, type HotspotMode, type HotspotPosition, type HotspotScaleMode, ImageHotspot, type ImageHotspotDefinition, type ImageHotspotProps, MAX_HOTSPOT_PITCH, PanoView, type PanoViewHandle, type PanoViewProps, type PanoViewState, type PanoramaControlsOptions, type PanoramaPointerEvent, type PanoramaScene, PanoramaScenes, type PanoramaScenesProps, type PanoramaTransition, type PanoramaTransitionEndEvent, type PanoramaTransitionErrorEvent, type PanoramaTransitionPreset, type PointHotspotDefinition, type PointHotspotDefinitionBase, PolygonHotspot, type PolygonHotspotDefinition, type PolygonHotspotProps, type PolygonValidationCode, type PolygonValidationIssue, type PolygonVerticesChangeEvent, PolylineHotspot, type PolylineHotspotDefinition, type PolylineHotspotProps, type PolylineValidationIssue, type PolylineVerticesChangeEvent, type RectangleGraphic, type RingGraphic, type SequenceFrameDirection, type SequenceFrameEvent, SequenceHotspot, type SequenceHotspotDefinition, type SequenceHotspotErrorEvent, type SequenceHotspotProps, type SequenceLoadProgress, type SequencePlaybackState, type SetPanoViewOptions, Sphere, type SpherePanoramaScene, type SphereProps, type SvgGraphic, type SvgPathGraphic, Tile, type TileAddress, type TileLoadError, type TileLoadProgress, type TileMultiresConfig, type TilePanoramaScene, type TileProps, VideoHotspot, type VideoHotspotDefinition, type VideoHotspotErrorEvent, type VideoHotspotProps, type VideoPlaybackState, clampPanoPitch, normalizePanoPosition, normalizePanoYaw, panoPositionToVector3, unwrapPolygonVertices, validatePolygonVertices, validatePolylineVertices, vector3ToPanoPosition };
1039
+ export { type ArrowGraphic, AutoRotate, type AutoRotateProps, type CircleGraphic, type CubeFaceCode, DEFAULT_HOTSPOT_TOOLTIP_OFFSET, DEFAULT_PANO_CURSORS, type DiamondGraphic, type GraphicDefinition, GraphicHotspot, type GraphicHotspotDefinition, type GraphicHotspotProps, type HotspotCommonProps, type HotspotDefinition, type HotspotDefinitionBase, type HotspotDragEvent, type HotspotInputSource, type HotspotInteractionEvent, type HotspotMode, type HotspotPosition, type HotspotScaleMode, type HotspotTooltipContent, type HotspotTooltipPlacement, type HotspotTooltipTrigger, IframeHotspot, type IframeHotspotDefinition, type IframeHotspotProps, type IframePointerPolicy, ImageHotspot, type ImageHotspotDefinition, type ImageHotspotProps, type KeyboardControlAction, type KeyboardControlKeys, KeyboardControls, type KeyboardControlsProps, MAX_HOTSPOT_PITCH, MIN_PANO_CONTEXT_MENU_BACKGROUND_OPACITY, type MouseControlButton, MouseControls, type MouseControlsOptions, type MouseControlsProps, PanoContextMenu, type PanoContextMenuActionItem, type PanoContextMenuAppearance, type PanoContextMenuEntry, type PanoContextMenuItem, type PanoContextMenuPresetActions, type PanoContextMenuPresetId, type PanoContextMenuPresetRef, type PanoContextMenuPresets, type PanoContextMenuProps, type PanoContextMenuRenderProps, type PanoContextMenuSelectContext, type PanoContextMenuSeparatorItem, type PanoCursor, type PanoCursors, type PanoEventBus, type PanoEventListener, type PanoEventMap, type PanoEventType, PanoEvents, type PanoEventsProps, type PanoResizeEvent, PanoViewer, type PanoViewerHandle, type PanoViewerProps, type PanoViewerState, type PanoWheelEvent, type PanoramaControlsOptions, type PanoramaPointerEvent, type PointHotspotDefinition, type PointHotspotDefinitionBase, PolygonHotspot, type PolygonHotspotDefinition, type PolygonHotspotProps, type PolygonValidationCode, type PolygonValidationIssue, type PolygonVerticesChangeEvent, PolylineHotspot, type PolylineHotspotDefinition, type PolylineHotspotProps, type PolylineValidationIssue, type PolylineVerticesChangeEvent, type RectangleGraphic, type RingGraphic, type Scene, type SceneTransition, type SceneTransitionEndEvent, type SceneTransitionErrorEvent, type SceneTransitionPreset, Scenes, type ScenesProps, type SequenceFrameDirection, type SequenceFrameEvent, SequenceHotspot, type SequenceHotspotDefinition, type SequenceHotspotErrorEvent, type SequenceHotspotProps, type SequenceLoadProgress, type SequencePlaybackState, type SetPanoViewerOptions, Sphere, type SphereProps, type SphereScene, type StarGraphic, type SvgGraphic, type SvgPathGraphic, TextHotspot, type TextHotspotAlign, type TextHotspotDefinition, type TextHotspotFontStyle, type TextHotspotProps, type TextHotspotStyle, type TextHotspotVerticalAlign, type TextHotspotWhiteSpace, Tile, type TileAddress, type TileLoadError, type TileLoadProgress, type TileMultiresConfig, type TileProps, type TileScene, TouchControls, type TouchControlsOptions, type TouchControlsProps, type TriangleGraphic, VideoHotspot, type VideoHotspotDefinition, type VideoHotspotErrorEvent, type VideoHotspotProps, type VideoPlaybackState, type ViewInteractionEvent, type ViewInteractionSource, clampPanoPitch, composePanoContextMenuItems, createDefaultPanoContextMenuItems, createPanoContextMenuPresets, cycleSceneId, normalizePanoPosition, normalizePanoYaw, panoPositionToVector3, resolvePanoContextMenuEntries, unwrapPolygonVertices, usePanoEvents, validatePolygonVertices, validatePolylineVertices, vector3ToPanoPosition };