@terraware/web-components 5.0.27 → 5.1.1-rc.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.
Files changed (311) hide show
  1. package/components/AntSwitch/index.js +19 -22
  2. package/components/Autocomplete/Autocomplete.js +106 -130
  3. package/components/Badge/index.js +28 -29
  4. package/components/BusySpinner/index.js +40 -45
  5. package/components/Button/Button.js +41 -47
  6. package/components/Checkbox.js +64 -63
  7. package/components/Confirm/index.js +74 -83
  8. package/components/DatePicker/DatePicker.js +138 -141
  9. package/components/DialogBox/DialogBox.js +111 -118
  10. package/components/Divisor.js +18 -18
  11. package/components/Dropdown.js +66 -94
  12. package/components/EditableTable/index.js +211 -271
  13. package/components/ErrorBox/ErrorBox.js +47 -49
  14. package/components/FileChooser/index.js +117 -135
  15. package/components/FormBottomBar/index.js +75 -84
  16. package/components/Icon/Icon.js +12 -20
  17. package/components/Icon/icons/index.js +256 -256
  18. package/components/IconTooltip/index.js +49 -60
  19. package/components/Map/MapBox.js +545 -452
  20. package/components/Map/MapContainer.js +25 -29
  21. package/components/Map/MapDateSliderControl.js +64 -64
  22. package/components/Map/MapDrawer.js +41 -47
  23. package/components/Map/MapLegend.js +176 -172
  24. package/components/Map/MapViewStyleControl.js +59 -63
  25. package/components/Map/ReactMapboxWrapper.js +3 -2
  26. package/components/Map/index.js +161 -180
  27. package/components/Map/types.js +12 -17
  28. package/components/Map/useMaintainLayerOrder.js +16 -26
  29. package/components/Markdown/index.js +25 -26
  30. package/components/Message/Message.js +73 -76
  31. package/components/MultiSelect/index.js +112 -124
  32. package/components/Navbar/NavFooter.js +9 -13
  33. package/components/Navbar/NavItem.js +70 -76
  34. package/components/Navbar/NavSection.js +17 -19
  35. package/components/Navbar/Navbar.js +39 -46
  36. package/components/Navbar/SubNavbar.js +9 -13
  37. package/components/Note.js +18 -22
  38. package/components/OverlayModal/OverlayModal.js +56 -63
  39. package/components/PageForm/index.js +33 -41
  40. package/components/PhotoChooser/index.js +165 -173
  41. package/components/PhotosCarousel/PhotoSlide.js +32 -35
  42. package/components/PhotosCarousel/index.js +80 -85
  43. package/components/PhotosCarousel/usePhotosCarousel.js +69 -76
  44. package/components/Pill/index.js +41 -45
  45. package/components/PillList/index.js +17 -24
  46. package/components/PlacementWrapper/index.js +38 -59
  47. package/components/PopoverMenu/Popover.js +68 -85
  48. package/components/PopoverMenu/index.js +51 -56
  49. package/components/PopoverMultiSelect/index.js +52 -59
  50. package/components/ProgressCircle/ProgressCircle.js +28 -32
  51. package/components/RadioButton.js +17 -19
  52. package/components/Select/Select.js +13 -15
  53. package/components/Select/SelectT.js +235 -250
  54. package/components/Separator/index.js +14 -17
  55. package/components/Size.js +0 -1
  56. package/components/Slider/index.js +43 -56
  57. package/components/Stepper/index.d.ts +33 -0
  58. package/components/Stepper/index.d.ts.map +1 -0
  59. package/components/Stepper/index.js +66 -0
  60. package/components/SummaryBox.js +70 -72
  61. package/components/Tabs/index.js +133 -135
  62. package/components/TextTruncated/index.js +117 -130
  63. package/components/Textfield/Textfield.js +158 -190
  64. package/components/Textfield/TruncatedTextArea.js +70 -84
  65. package/components/TimelineSlider/TimelineMarker.js +25 -30
  66. package/components/TimelineSlider/TimelineRail.js +8 -11
  67. package/components/TimelineSlider/index.js +64 -66
  68. package/components/TimelineSliderV2/ClusterBadge.js +25 -29
  69. package/components/TimelineSliderV2/TimelineDot.js +31 -35
  70. package/components/TimelineSliderV2/TimelineRail.js +8 -11
  71. package/components/TimelineSliderV2/index.js +121 -103
  72. package/components/TimelineSliderV2/layout.js +124 -147
  73. package/components/TimelineSliderV2/types.js +0 -1
  74. package/components/Tooltip/Tooltip.js +47 -56
  75. package/components/ViewPhotosDialog/index.js +28 -35
  76. package/components/VirtualWalkthrough/Annotation.js +163 -207
  77. package/components/VirtualWalkthrough/AnnotationEditPane.js +198 -184
  78. package/components/VirtualWalkthrough/AnnotationPanel.js +187 -199
  79. package/components/VirtualWalkthrough/Application.js +31 -34
  80. package/components/VirtualWalkthrough/AutoRotator.js +85 -223
  81. package/components/VirtualWalkthrough/BlockingSpinner.js +26 -28
  82. package/components/VirtualWalkthrough/BoundaryRing.js +30 -34
  83. package/components/VirtualWalkthrough/BoundaryWall.js +32 -36
  84. package/components/VirtualWalkthrough/CameraInfo.js +100 -89
  85. package/components/VirtualWalkthrough/ControlsInfoPane.js +254 -195
  86. package/components/VirtualWalkthrough/GradientSky.js +72 -73
  87. package/components/VirtualWalkthrough/SplatControls.js +209 -221
  88. package/components/VirtualWalkthrough/SplatCrop.js +21 -20
  89. package/components/VirtualWalkthrough/SplatFadeCrop.js +21 -20
  90. package/components/VirtualWalkthrough/SplatModel.js +65 -85
  91. package/components/VirtualWalkthrough/SplatRevealRain.js +41 -46
  92. package/components/VirtualWalkthrough/TfAnnotationManager.js +197 -379
  93. package/components/VirtualWalkthrough/TfXrNavigation.js +73 -162
  94. package/components/VirtualWalkthrough/VirtualWalkthroughViewer.js +438 -431
  95. package/components/VirtualWalkthrough/VrAnnotationPanel.js +18 -22
  96. package/components/VirtualWalkthrough/XrAnnotationInteraction.js +14 -17
  97. package/components/VirtualWalkthrough/XrExitButton.js +14 -17
  98. package/components/VirtualWalkthrough/XrGazeDwell.js +14 -17
  99. package/components/VirtualWalkthrough/XrPointerRay.js +14 -17
  100. package/components/VirtualWalkthrough/XrStartPose.js +67 -121
  101. package/components/VirtualWalkthrough/boundary-ring.js +87 -117
  102. package/components/VirtualWalkthrough/boundary-wall.js +175 -258
  103. package/components/VirtualWalkthrough/camera-adoption.js +18 -64
  104. package/components/VirtualWalkthrough/groundPlane.js +32 -47
  105. package/components/VirtualWalkthrough/gsplat-fade-crop-effect.js +35 -35
  106. package/components/VirtualWalkthrough/splatFormat.js +13 -47
  107. package/components/VirtualWalkthrough/useAdoptedCamera.js +23 -44
  108. package/components/VirtualWalkthrough/useRestartOnVr.js +26 -37
  109. package/components/VirtualWalkthrough/useXrRenderTuning.js +33 -54
  110. package/components/VirtualWalkthrough/vr-annotation-panel-layout.js +67 -99
  111. package/components/VirtualWalkthrough/vr-annotation-panel.js +403 -433
  112. package/components/VirtualWalkthrough/vr-annotation-scroll.js +10 -28
  113. package/components/VirtualWalkthrough/walkthrough-camera.js +204 -329
  114. package/components/VirtualWalkthrough/xr-annotation-candidate-buffer.js +39 -80
  115. package/components/VirtualWalkthrough/xr-annotation-candidates.js +6 -18
  116. package/components/VirtualWalkthrough/xr-annotation-interaction.js +31 -56
  117. package/components/VirtualWalkthrough/xr-annotation-targeting.js +22 -38
  118. package/components/VirtualWalkthrough/xr-button-arming.js +7 -17
  119. package/components/VirtualWalkthrough/xr-button-hold.js +22 -36
  120. package/components/VirtualWalkthrough/xr-exit-button-mask.js +22 -36
  121. package/components/VirtualWalkthrough/xr-exit-button.js +148 -207
  122. package/components/VirtualWalkthrough/xr-face-buttons.js +19 -29
  123. package/components/VirtualWalkthrough/xr-gaze-dwell-state.js +23 -34
  124. package/components/VirtualWalkthrough/xr-gaze-dwell.js +107 -144
  125. package/components/VirtualWalkthrough/xr-interactive-ui.js +12 -24
  126. package/components/VirtualWalkthrough/xr-pointer-ray.js +13 -20
  127. package/components/VirtualWalkthrough/xr-progress-pie-material.js +117 -88
  128. package/components/VirtualWalkthrough/xr-progress-pie.js +1 -10
  129. package/components/VirtualWalkthrough/xr-ray-quad.js +16 -30
  130. package/components/VirtualWalkthrough/xr-render-tuning.js +17 -48
  131. package/components/VirtualWalkthrough/xr-scene-bounds.js +21 -37
  132. package/components/VirtualWalkthrough/xr-start-pose.js +27 -73
  133. package/components/VirtualWalkthrough/xr-teleport-gesture.js +16 -42
  134. package/components/svg/BlobbyGrayIconImage.js +41 -39
  135. package/components/svg/BlobbyGrayIconImport.js +41 -39
  136. package/components/svg/BlobbyGrayIconUploadToTheCloud.js +41 -39
  137. package/components/svg/BlobbyIconCloudChecked.js +202 -164
  138. package/components/svg/BlobbyIconExportOrUploadPhoto.js +202 -164
  139. package/components/svg/BlobbyIconFolder.js +202 -164
  140. package/components/svg/BlobbyIconGraphReport.js +202 -164
  141. package/components/svg/BlobbyIconHappy.js +202 -164
  142. package/components/svg/BlobbyIconHeartMonitor.js +202 -164
  143. package/components/svg/BlobbyIconLeaf.js +202 -164
  144. package/components/svg/BlobbyIconLibrary.js +202 -164
  145. package/components/svg/BlobbyIconNursery.js +204 -166
  146. package/components/svg/BlobbyIconOrganization.js +202 -164
  147. package/components/svg/BlobbyIconParchment.js +202 -164
  148. package/components/svg/BlobbyIconPeople.js +202 -164
  149. package/components/svg/BlobbyIconSeedBank.js +202 -164
  150. package/components/svg/BlobbyIconSeedling.js +202 -164
  151. package/components/svg/BlobbyIconSeeds.js +202 -164
  152. package/components/svg/BlobbyIconSite.js +206 -167
  153. package/components/svg/BlobbyIconSparkles.js +202 -164
  154. package/components/svg/BlobbyIconWrench.js +202 -164
  155. package/components/svg/Bug.js +19 -21
  156. package/components/svg/Calendar.js +19 -21
  157. package/components/svg/CaretDown.js +19 -21
  158. package/components/svg/CaretLeft.js +19 -21
  159. package/components/svg/CaretRight.js +19 -21
  160. package/components/svg/CaretUp.js +19 -21
  161. package/components/svg/ChevronDown.js +19 -21
  162. package/components/svg/ChevronUp.js +19 -21
  163. package/components/svg/Close.js +19 -21
  164. package/components/svg/Critical.js +19 -21
  165. package/components/svg/Edit.js +202 -164
  166. package/components/svg/Error.js +19 -21
  167. package/components/svg/Filter.js +19 -21
  168. package/components/svg/Folder.js +19 -21
  169. package/components/svg/Help.js +19 -21
  170. package/components/svg/Home.js +19 -21
  171. package/components/svg/IconAdd.js +19 -21
  172. package/components/svg/IconArrowRight.js +21 -23
  173. package/components/svg/IconBusinessNetwork.js +19 -21
  174. package/components/svg/IconCalendar.js +19 -21
  175. package/components/svg/IconCancel.js +19 -21
  176. package/components/svg/IconChargingBattery.js +19 -21
  177. package/components/svg/IconChecklist.js +21 -23
  178. package/components/svg/IconCheckmark.js +19 -21
  179. package/components/svg/IconCoinInHand.js +19 -21
  180. package/components/svg/IconColumns.js +19 -21
  181. package/components/svg/IconComment.js +20 -22
  182. package/components/svg/IconDashboard.js +19 -21
  183. package/components/svg/IconDataMigration.js +19 -21
  184. package/components/svg/IconDocument.js +21 -23
  185. package/components/svg/IconDownloadFromTheCloud.js +21 -23
  186. package/components/svg/IconEdit.js +21 -23
  187. package/components/svg/IconExpand.js +21 -23
  188. package/components/svg/IconExport.js +19 -21
  189. package/components/svg/IconExternalLink.js +19 -21
  190. package/components/svg/IconEye.js +19 -21
  191. package/components/svg/IconEyeOff.js +19 -21
  192. package/components/svg/IconFile.js +19 -21
  193. package/components/svg/IconFolder.js +19 -21
  194. package/components/svg/IconFullScreen.js +20 -22
  195. package/components/svg/IconFutures.js +19 -21
  196. package/components/svg/IconGraphReport.js +19 -21
  197. package/components/svg/IconGrid.js +19 -21
  198. package/components/svg/IconHeartMonitor.js +19 -21
  199. package/components/svg/IconHelp.js +21 -23
  200. package/components/svg/IconHistory.js +19 -21
  201. package/components/svg/IconImport.js +19 -21
  202. package/components/svg/IconIndex.js +19 -21
  203. package/components/svg/IconLayers.js +19 -21
  204. package/components/svg/IconLibrary.js +20 -22
  205. package/components/svg/IconList.js +19 -21
  206. package/components/svg/IconLivePlant.js +19 -21
  207. package/components/svg/IconLocations.js +19 -21
  208. package/components/svg/IconMail.js +19 -21
  209. package/components/svg/IconManager.js +19 -21
  210. package/components/svg/IconMap.js +19 -21
  211. package/components/svg/IconMarker.js +19 -21
  212. package/components/svg/IconMenu.js +19 -21
  213. package/components/svg/IconMenuHorizontal.js +19 -21
  214. package/components/svg/IconModule.js +19 -21
  215. package/components/svg/IconMyLocation.js +19 -21
  216. package/components/svg/IconNote.js +21 -23
  217. package/components/svg/IconNursery.js +21 -23
  218. package/components/svg/IconOrg.js +19 -21
  219. package/components/svg/IconParchment.js +19 -21
  220. package/components/svg/IconPhoto.js +19 -21
  221. package/components/svg/IconPlantsFilled.js +19 -21
  222. package/components/svg/IconRedo.js +19 -21
  223. package/components/svg/IconRestorationSite.js +19 -21
  224. package/components/svg/IconSeedBank.js +19 -21
  225. package/components/svg/IconSeedling.js +19 -21
  226. package/components/svg/IconSettings.js +19 -21
  227. package/components/svg/IconSlice.js +19 -21
  228. package/components/svg/IconSubmit.js +19 -21
  229. package/components/svg/IconSubtract.js +21 -23
  230. package/components/svg/IconSynced.js +19 -21
  231. package/components/svg/IconTrashCan.js +19 -21
  232. package/components/svg/IconTreasureMap.js +19 -21
  233. package/components/svg/IconUnavailable.js +19 -21
  234. package/components/svg/IconUndo.js +19 -21
  235. package/components/svg/IconVariable.js +19 -21
  236. package/components/svg/IconVideo.js +30 -31
  237. package/components/svg/IconWifi.js +19 -21
  238. package/components/svg/Info.js +19 -21
  239. package/components/svg/Key.js +19 -21
  240. package/components/svg/Leaf.js +19 -21
  241. package/components/svg/Lock.js +19 -21
  242. package/components/svg/Logo.js +48 -43
  243. package/components/svg/MenuVertical.js +19 -21
  244. package/components/svg/Notification.js +19 -21
  245. package/components/svg/Person.js +19 -21
  246. package/components/svg/Plus.js +19 -21
  247. package/components/svg/RestorationSite.js +19 -21
  248. package/components/svg/Search.js +19 -21
  249. package/components/svg/Seeds.js +19 -21
  250. package/components/svg/Site.js +19 -21
  251. package/components/svg/Sparkles.js +19 -21
  252. package/components/svg/Species.js +19 -21
  253. package/components/svg/Species2.js +202 -164
  254. package/components/svg/Spinner.js +54 -48
  255. package/components/svg/Star.js +19 -21
  256. package/components/svg/Success.js +19 -21
  257. package/components/svg/SuccessFilled.js +19 -21
  258. package/components/svg/TerrawareLogoDesktop.js +55 -49
  259. package/components/svg/TerrawareLogoMobile.js +25 -26
  260. package/components/svg/Touchscreen.js +19 -21
  261. package/components/svg/UploadCloud.js +202 -164
  262. package/components/svg/Warning.js +19 -21
  263. package/components/svg/WelcomeClipboard.js +156 -133
  264. package/components/svg/index.js +129 -129
  265. package/components/table/EnhancedTableToolbar.js +68 -74
  266. package/components/table/EnhancedTableToolbarV2.js +31 -41
  267. package/components/table/TableCellRenderer.js +196 -231
  268. package/components/table/TableHeader.js +71 -73
  269. package/components/table/TableHeaderItem.js +97 -102
  270. package/components/table/density.js +18 -19
  271. package/components/table/index.js +350 -369
  272. package/components/table/sort.js +27 -52
  273. package/components/table/types.js +0 -1
  274. package/components/types/index.js +0 -1
  275. package/hooks/cameraEntityContext.js +2 -13
  276. package/hooks/useBoolean.js +17 -13
  277. package/hooks/useCameraPosition.js +56 -56
  278. package/hooks/useDevicePerformance.js +17 -17
  279. package/hooks/useXr.js +85 -87
  280. package/index.d.ts +3 -1
  281. package/index.d.ts.map +1 -1
  282. package/index.js +59 -58
  283. package/package.json +1 -1
  284. package/setupTests.js +0 -4
  285. package/strings/csv/en.csv +1 -0
  286. package/strings/csv/es.csv +1 -0
  287. package/strings/csv/fr.csv +1 -0
  288. package/strings/export.js +111 -170
  289. package/strings/index.js +25 -54
  290. package/strings/locales.js +21 -41
  291. package/strings/strings-en.d.ts +1 -0
  292. package/strings/strings-en.d.ts.map +1 -1
  293. package/strings/strings-en.js +50 -51
  294. package/strings/strings-es.d.ts +1 -0
  295. package/strings/strings-es.d.ts.map +1 -1
  296. package/strings/strings-es.js +50 -51
  297. package/strings/strings-fr.d.ts +1 -0
  298. package/strings/strings-fr.d.ts.map +1 -1
  299. package/strings/strings-fr.js +50 -51
  300. package/strings/strings-gx.d.ts +1 -0
  301. package/strings/strings-gx.d.ts.map +1 -1
  302. package/strings/strings-gx.js +50 -51
  303. package/style-dictionary-dist/TerrawareTheme.js +186 -186
  304. package/theme.js +74 -76
  305. package/utils/color.js +8 -15
  306. package/utils/date.js +42 -108
  307. package/utils/index.js +4 -4
  308. package/utils/preventDefaultEvent.js +3 -3
  309. package/utils/text.js +11 -11
  310. package/utils/useDeviceInfo.js +42 -79
  311. package/virtualWalkthrough.js +23 -23
@@ -1,438 +1,445 @@
1
- import { useState, useCallback, useRef, useEffect, useMemo } from 'react';
2
- import { useTheme } from '@mui/material';
3
- import { Entity } from '@playcanvas/react';
4
- import { Script, Camera } from '@playcanvas/react/components';
5
- import { useApp } from '@playcanvas/react/hooks';
6
- import { Vec3, Color } from 'playcanvas';
7
- import { XrControllers } from 'playcanvas/scripts/esm/xr/xr-controllers.mjs';
8
- import { CameraEntityContext } from '../../hooks/cameraEntityContext.js';
9
- import { useCameraPosition } from '../../hooks/useCameraPosition.js';
10
- import { useDevicePerformance } from '../../hooks/useDevicePerformance.js';
11
- import useXr from '../../hooks/useXr.js';
12
- import Annotation from './Annotation.js';
13
- import AnnotationPanel from './AnnotationPanel.js';
14
- import { AutoRotator } from './AutoRotator.js';
15
- import BoundaryRing from './BoundaryRing.js';
16
- import BoundaryWall from './BoundaryWall.js';
17
- import GradientSky from './GradientSky.js';
18
- import SplatControls from './SplatControls.js';
19
- import SplatModel from './SplatModel.js';
20
- import { TfAnnotationManager } from './TfAnnotationManager.js';
21
- import { TfXrNavigation } from './TfXrNavigation.js';
22
- import VrAnnotationPanel from './VrAnnotationPanel.js';
23
- import XrAnnotationInteraction from './XrAnnotationInteraction.js';
24
- import XrExitButton from './XrExitButton.js';
25
- import XrGazeDwell from './XrGazeDwell.js';
26
- import XrPointerRay from './XrPointerRay.js';
27
- import { XrStartPose } from './XrStartPose.js';
28
- import useAdoptedCamera from './useAdoptedCamera.js';
29
- import useXrRenderTuning from './useXrRenderTuning.js';
30
- import { WalkthroughCamera } from './walkthrough-camera.js';
31
- import { rayHitsInteractiveUi } from './xr-interactive-ui.js';
32
- import { jsx, jsxs } from 'react/jsx-runtime';
33
-
34
- const DEFAULT_FOCUS_POINT = [0, 0.1, 0];
35
- const DEFAULT_POSITION = [1, 0.1, 0];
36
-
37
- // How far outside the clamp radius the boundary wall stands. Without it the wall would be coplanar
38
- // with the surface the head is clamped to, so a pinned user would have it in their face and through
39
- // their near clip plane.
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+ import { useTheme } from "@mui/material";
4
+ import { Entity } from "@playcanvas/react";
5
+ import { Camera, Script } from "@playcanvas/react/components";
6
+ import { useApp } from "@playcanvas/react/hooks";
7
+ import { Color, Vec3 } from "playcanvas";
8
+ import { XrControllers } from "playcanvas/scripts/esm/xr/xr-controllers.mjs";
9
+ import { CameraEntityContext } from "../../hooks/cameraEntityContext.js";
10
+ import { useCameraPosition } from "../../hooks/useCameraPosition.js";
11
+ import { useDevicePerformance } from "../../hooks/useDevicePerformance.js";
12
+ import { useXr } from "../../hooks/useXr.js";
13
+ import Annotation from "./Annotation.js";
14
+ import AnnotationPanel from "./AnnotationPanel.js";
15
+ import { AutoRotator } from "./AutoRotator.js";
16
+ import BoundaryRing from "./BoundaryRing.js";
17
+ import BoundaryWall from "./BoundaryWall.js";
18
+ import GradientSky from "./GradientSky.js";
19
+ import SplatControls from "./SplatControls.js";
20
+ import SplatModel from "./SplatModel.js";
21
+ import { TfAnnotationManager } from "./TfAnnotationManager.js";
22
+ import { TfXrNavigation } from "./TfXrNavigation.js";
23
+ import VrAnnotationPanel from "./VrAnnotationPanel.js";
24
+ import XrAnnotationInteraction from "./XrAnnotationInteraction.js";
25
+ import XrExitButton from "./XrExitButton.js";
26
+ import XrGazeDwell from "./XrGazeDwell.js";
27
+ import XrPointerRay from "./XrPointerRay.js";
28
+ import { XrStartPose } from "./XrStartPose.js";
29
+ import { useAdoptedCamera } from "./useAdoptedCamera.js";
30
+ import { useXrRenderTuning } from "./useXrRenderTuning.js";
31
+ import { WalkthroughCamera } from "./walkthrough-camera.js";
32
+ import { rayHitsInteractiveUi } from "./xr-interactive-ui.js";
33
+ const DEFAULT_FOCUS_POINT = [
34
+ 0,
35
+ 0.1,
36
+ 0
37
+ ];
38
+ const DEFAULT_POSITION = [
39
+ 1,
40
+ 0.1,
41
+ 0
42
+ ];
40
43
  const WALL_INSET = 0.25;
41
-
42
- /**
43
- * Largest world size (metres) a hotspot is allowed to reach as the camera approaches it, so it
44
- * stops growing rather than filling the view from close up.
45
- */
46
44
  const MAX_HOTSPOT_WORLD_SIZE = 0.75;
47
-
48
- /**
49
- * Every coordinate, distance and size in this component is world-space, in the metres an XR
50
- * headset imposes on the scene: `scaleFactor` converts the splat's own arbitrary units to them,
51
- * and is applied to nothing but the splat itself.
52
- */
53
-
54
- const VirtualWalkthroughViewer = ({
55
- splatSrc,
56
- splatFormat,
57
- camera = /*#__PURE__*/jsx(Camera, {
45
+ const VirtualWalkthroughViewer = ({ splatSrc, splatFormat, camera = /*#__PURE__*/ jsx(Camera, {
58
46
  clearColor: "#EAF8FF",
59
47
  fov: 60
60
- }),
61
- origin = DEFAULT_FOCUS_POINT,
62
- cameraPosition = DEFAULT_POSITION,
63
- sceneBounds,
64
- groundPlane: groundPlaneProp,
65
- skyColor,
66
- groundColor,
67
- averageCameraHeight = 0,
68
- scaleFactor = 1,
69
- splatModelProps,
70
- autoStartVr = false,
71
- onXrExit,
72
- onXrClose,
73
- annotations,
74
- onSaveAnnotations,
75
- editable = false,
76
- showFreeFly = false,
77
- isFullScreen = false,
78
- onToggleFullScreen,
79
- maxImagesPerAnnotation
80
- }) => {
81
- const theme = useTheme();
82
- // Held as state so the effects and hooks that address these entities re-run once they
83
- // exist. Addressed directly: a viewer mounted into a host's scene shares the graph
84
- // with the host's entities, so the camera can be found by component type.
85
- const [cameraRoot, setCameraRoot] = useState(null);
86
- const [cameraEntity, setCameraEntity] = useState(null);
87
- const adoptedCamera = useAdoptedCamera(cameraRoot, cameraEntity);
88
- // The entity carrying the live camera component: the viewer's own, or the host's while adopted.
89
- // Everything that poses the camera or projects through it addresses this rather than the entity
90
- // the viewer mounts a camera of its own on, which holds nothing while a camera is adopted.
91
- const activeCamera = adoptedCamera ?? cameraEntity;
92
- const {
93
- setCamera
94
- } = useCameraPosition(activeCamera);
95
- const {
96
- isHighPerformance
97
- } = useDevicePerformance();
98
- const app = useApp();
99
- const [showAnnotations, setShowAnnotations] = useState(true);
100
- const [autoRotate, setAutoRotate] = useState(true);
101
- const [isEdit, setIsEdit] = useState(false);
102
- const [isFreeFly, setIsFreeFly] = useState(false);
103
- const [selectedAnnotationIndex, setSelectedAnnotationIndex] = useState(-1);
104
- const [localAnnotations, setLocalAnnotations] = useState(annotations);
105
- const [isTextFieldFocused, setIsTextFieldFocused] = useState(false);
106
- const [viewingAnnotation, setViewingAnnotation] = useState(null);
107
- const [viewingAnnotationIndex, setViewingAnnotationIndex] = useState(-1);
108
- const [viewedScreenPos, setViewedScreenPos] = useState(null);
109
- const reportXrError = useCallback(error => {
110
- console.warn(error.message, error);
111
- onXrExit?.(error);
112
- }, [onXrExit]);
113
- const {
114
- isCurrentlyInXr,
115
- isCurrentlyInVr,
116
- isCurrentlyInAr,
117
- isXrAvailable,
118
- startXr
119
- } = useXr({
120
- onError: reportXrError
121
- });
122
- useXrRenderTuning();
123
- const autoStartRequested = useRef(false);
124
-
125
- // Edge-triggered so that ending a session doesn't pull the user straight back into one. The ref
126
- // is written before the early returns, so lowering the prop re-arms the next rising edge.
127
- useEffect(() => {
128
- const isRisingEdge = autoStartVr && !autoStartRequested.current;
129
- autoStartRequested.current = autoStartVr;
130
- if (!isRisingEdge || isCurrentlyInXr) {
131
- return;
132
- }
133
- if (!isXrAvailable('VR')) {
134
- reportXrError(new Error('A VR session was requested, but this device reports no immersive VR support'));
135
- return;
136
- }
137
- startXr('VR');
138
- }, [autoStartVr, isCurrentlyInXr, isXrAvailable, startXr, reportXrError]);
139
- const wasInXr = useRef(false);
140
-
141
- // Edge-detected rather than reported whenever the viewer is out of XR, which would fire on mount
142
- // and tell a caller a session had ended before one ever began.
143
- useEffect(() => {
144
- if (wasInXr.current && !isCurrentlyInXr) {
145
- onXrExit?.();
146
- }
147
- wasInXr.current = isCurrentlyInXr;
148
- }, [isCurrentlyInXr, onXrExit]);
149
- const sceneBoundsRadius = useMemo(() => {
150
- if (sceneBounds?.m !== undefined) {
151
- return sceneBounds.m;
152
- }
153
- const dx = cameraPosition[0] - origin[0];
154
- const dy = cameraPosition[1] - origin[1];
155
- const dz = cameraPosition[2] - origin[2];
156
- return Math.sqrt(dx * dx + dy * dy + dz * dz);
157
- }, [cameraPosition, sceneBounds, origin]);
158
- const sceneBoundsCenter = useMemo(() => sceneBounds ? new Vec3(sceneBounds.x, sceneBounds.y, sceneBounds.z) : new Vec3(origin[0], cameraPosition[1], origin[2]), [sceneBounds, origin, cameraPosition]);
159
- const groundPlane = useMemo(() => groundPlaneProp?.length === 3 ? groundPlaneProp.map(p => new Vec3(p[0], p[1], p[2])) : [], [groundPlaneProp]);
160
-
161
- // Also runs when a session ends. WalkthroughCamera is unmounted for the duration of a session, so
162
- // the camera entity is left holding the last head pose — an eye height above wherever in the rig
163
- // the user was standing — which is neither where nor how high the walkthrough left off.
164
- useEffect(() => {
165
- if (isCurrentlyInXr) {
166
- return;
167
- }
168
- setCamera(origin, cameraPosition);
169
- }, [origin, cameraPosition, setCamera, isCurrentlyInXr]);
170
-
171
- // Re-applied when a session ends for the same reason: the script that comes back is a new
172
- // instance, and without the ground plane it walks the camera at the bounds centre's height
173
- // instead of an eye height above the ground.
174
- useEffect(() => {
175
- if (!groundPlane.length || isCurrentlyInXr) {
176
- return;
177
- }
178
- // @ts-expect-error - scripts are added dynamically to the entity
179
- const walkthroughCam = cameraRoot?.script?.walkthroughCamera;
180
- if (walkthroughCam) {
181
- // Should be changed to a react prop if shallowEquals in playcanvas/react is fixed (see https://github.com/playcanvas/react/pull/298)
182
- walkthroughCam.groundPlane = groundPlane;
183
- }
184
- }, [groundPlane, cameraRoot, isCurrentlyInXr]);
185
- useEffect(() => {
186
- // Set imperatively for the same reason as BoundaryRing: boundsCenter is a Vec3, and the
187
- // @playcanvas/react memo() comparator stops at the first prop with an .equals() method.
188
- // @ts-expect-error - scripts are added dynamically to the entity
189
- const navigation = cameraRoot?.script?.tfXrNavigation;
190
- if (navigation) {
191
- navigation.boundsCenter = sceneBoundsCenter;
192
- navigation.boundsRadius = sceneBoundsRadius;
193
- }
194
- }, [cameraRoot, sceneBoundsCenter, sceneBoundsRadius]);
195
- const handleToggleFreeFly = useCallback(() => {
196
- const newFreeFly = !isFreeFly;
197
- // @ts-expect-error - scripts are added dynamically to the entity
198
- const walkthroughCam = cameraRoot?.script?.walkthroughCamera;
199
- if (walkthroughCam) {
200
- walkthroughCam.freeFly = newFreeFly;
201
- }
202
- if (!newFreeFly) {
203
- setCamera(origin, cameraPosition);
204
- }
205
- setIsFreeFly(newFreeFly);
206
- }, [isFreeFly, cameraRoot, setCamera, origin, cameraPosition]);
207
- useEffect(() => {
208
- setLocalAnnotations(annotations);
209
- }, [annotations]);
210
- useEffect(() => {
211
- if (!isEdit) {
212
- setSelectedAnnotationIndex(-1);
213
- }
214
- }, [isEdit]);
215
- const handleAnnotationPositionChange = useCallback(position => {
216
- setLocalAnnotations(prev => {
217
- if (selectedAnnotationIndex === -1) {
218
- return prev;
219
- }
220
- const updated = [...prev];
221
- updated[selectedAnnotationIndex] = {
222
- ...updated[selectedAnnotationIndex],
223
- position
224
- };
225
- return updated;
48
+ }), origin = DEFAULT_FOCUS_POINT, cameraPosition = DEFAULT_POSITION, sceneBounds, groundPlane: groundPlaneProp, skyColor, groundColor, averageCameraHeight = 0, scaleFactor = 1, splatModelProps, autoStartVr = false, onXrExit, onXrClose, annotations, onSaveAnnotations, editable = false, showFreeFly = false, isFullScreen = false, onToggleFullScreen, maxImagesPerAnnotation })=>{
49
+ const theme = useTheme();
50
+ const [cameraRoot, setCameraRoot] = useState(null);
51
+ const [cameraEntity, setCameraEntity] = useState(null);
52
+ const adoptedCamera = useAdoptedCamera(cameraRoot, cameraEntity);
53
+ const activeCamera = adoptedCamera ?? cameraEntity;
54
+ const { setCamera } = useCameraPosition(activeCamera);
55
+ const { isHighPerformance } = useDevicePerformance();
56
+ const app = useApp();
57
+ const [showAnnotations, setShowAnnotations] = useState(true);
58
+ const [autoRotate, setAutoRotate] = useState(true);
59
+ const [isEdit, setIsEdit] = useState(false);
60
+ const [isFreeFly, setIsFreeFly] = useState(false);
61
+ const [selectedAnnotationIndex, setSelectedAnnotationIndex] = useState(-1);
62
+ const [localAnnotations, setLocalAnnotations] = useState(annotations);
63
+ const [isTextFieldFocused, setIsTextFieldFocused] = useState(false);
64
+ const [viewingAnnotation, setViewingAnnotation] = useState(null);
65
+ const [viewingAnnotationIndex, setViewingAnnotationIndex] = useState(-1);
66
+ const [viewedScreenPos, setViewedScreenPos] = useState(null);
67
+ const reportXrError = useCallback((error)=>{
68
+ console.warn(error.message, error);
69
+ onXrExit?.(error);
70
+ }, [
71
+ onXrExit
72
+ ]);
73
+ const { isCurrentlyInXr, isCurrentlyInVr, isCurrentlyInAr, isXrAvailable, startXr } = useXr({
74
+ onError: reportXrError
226
75
  });
227
- }, [selectedAnnotationIndex]);
228
- const handleSave = useCallback(() => {
229
- const saveAndClose = async () => {
230
- await onSaveAnnotations(localAnnotations);
231
- setIsEdit(false);
232
- setSelectedAnnotationIndex(-1);
233
- };
234
- void saveAndClose();
235
- }, [onSaveAnnotations, localAnnotations]);
236
- const handleCancel = useCallback(() => {
237
- setLocalAnnotations(annotations);
238
- setIsEdit(false);
239
- setSelectedAnnotationIndex(-1);
240
- }, [annotations]);
241
- const handleAddAnnotation = useCallback(() => {
242
- const newAnnotation = {
243
- position: origin,
244
- title: ''
245
- };
246
- setLocalAnnotations(prev => [...prev, newAnnotation]);
247
- setSelectedAnnotationIndex(localAnnotations.length);
248
- }, [origin, localAnnotations]);
249
- const handleDeleteAnnotation = useCallback(() => {
250
- if (selectedAnnotationIndex === -1) {
251
- return;
252
- }
253
- setLocalAnnotations(prev => prev.filter((_, index) => index !== selectedAnnotationIndex));
254
- setSelectedAnnotationIndex(-1);
255
- }, [selectedAnnotationIndex]);
256
- const handleDeselectAnnotation = useCallback(() => {
257
- setSelectedAnnotationIndex(-1);
258
- }, []);
259
- const handleAnnotationView = useCallback(
260
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
261
- (annotation, annotationIndex, screenX, screenY) => {
262
- setViewingAnnotation(annotation);
263
- setViewingAnnotationIndex(annotationIndex);
264
- // Cleared so the connector line waits for the hotspot's post-aim position
265
- // rather than briefly pointing at its old spot.
266
- setViewedScreenPos(null);
267
- }, []);
268
- const handleAnnotationScreenPositionUpdate = useCallback((_index, screenX, screenY, size) => {
269
- if (isCurrentlyInXr) {
270
- return;
271
- }
272
- // The scene is frozen while the panel is open, so guard against redundant
273
- // updates from the per-frame callback to avoid needless re-renders.
274
- setViewedScreenPos(prev => prev && prev.x === screenX && prev.y === screenY && prev.size === size ? prev : {
275
- x: screenX,
276
- y: screenY,
277
- size
76
+ useXrRenderTuning();
77
+ const autoStartRequested = useRef(false);
78
+ useEffect(()=>{
79
+ const isRisingEdge = autoStartVr && !autoStartRequested.current;
80
+ autoStartRequested.current = autoStartVr;
81
+ if (!isRisingEdge || isCurrentlyInXr) return;
82
+ if (!isXrAvailable('VR')) return void reportXrError(new Error('A VR session was requested, but this device reports no immersive VR support'));
83
+ startXr('VR');
84
+ }, [
85
+ autoStartVr,
86
+ isCurrentlyInXr,
87
+ isXrAvailable,
88
+ startXr,
89
+ reportXrError
90
+ ]);
91
+ const wasInXr = useRef(false);
92
+ useEffect(()=>{
93
+ if (wasInXr.current && !isCurrentlyInXr) onXrExit?.();
94
+ wasInXr.current = isCurrentlyInXr;
95
+ }, [
96
+ isCurrentlyInXr,
97
+ onXrExit
98
+ ]);
99
+ const sceneBoundsRadius = useMemo(()=>{
100
+ if (sceneBounds?.m !== void 0) return sceneBounds.m;
101
+ const dx = cameraPosition[0] - origin[0];
102
+ const dy = cameraPosition[1] - origin[1];
103
+ const dz = cameraPosition[2] - origin[2];
104
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
105
+ }, [
106
+ cameraPosition,
107
+ sceneBounds,
108
+ origin
109
+ ]);
110
+ const sceneBoundsCenter = useMemo(()=>sceneBounds ? new Vec3(sceneBounds.x, sceneBounds.y, sceneBounds.z) : new Vec3(origin[0], cameraPosition[1], origin[2]), [
111
+ sceneBounds,
112
+ origin,
113
+ cameraPosition
114
+ ]);
115
+ const groundPlane = useMemo(()=>groundPlaneProp?.length === 3 ? groundPlaneProp.map((p)=>new Vec3(p[0], p[1], p[2])) : [], [
116
+ groundPlaneProp
117
+ ]);
118
+ useEffect(()=>{
119
+ if (isCurrentlyInXr) return;
120
+ setCamera(origin, cameraPosition);
121
+ }, [
122
+ origin,
123
+ cameraPosition,
124
+ setCamera,
125
+ isCurrentlyInXr
126
+ ]);
127
+ useEffect(()=>{
128
+ if (!groundPlane.length || isCurrentlyInXr) return;
129
+ const walkthroughCam = cameraRoot?.script?.walkthroughCamera;
130
+ if (walkthroughCam) walkthroughCam.groundPlane = groundPlane;
131
+ }, [
132
+ groundPlane,
133
+ cameraRoot,
134
+ isCurrentlyInXr
135
+ ]);
136
+ useEffect(()=>{
137
+ const navigation = cameraRoot?.script?.tfXrNavigation;
138
+ if (navigation) {
139
+ navigation.boundsCenter = sceneBoundsCenter;
140
+ navigation.boundsRadius = sceneBoundsRadius;
141
+ }
142
+ }, [
143
+ cameraRoot,
144
+ sceneBoundsCenter,
145
+ sceneBoundsRadius
146
+ ]);
147
+ const handleToggleFreeFly = useCallback(()=>{
148
+ const newFreeFly = !isFreeFly;
149
+ const walkthroughCam = cameraRoot?.script?.walkthroughCamera;
150
+ if (walkthroughCam) walkthroughCam.freeFly = newFreeFly;
151
+ if (!newFreeFly) setCamera(origin, cameraPosition);
152
+ setIsFreeFly(newFreeFly);
153
+ }, [
154
+ isFreeFly,
155
+ cameraRoot,
156
+ setCamera,
157
+ origin,
158
+ cameraPosition
159
+ ]);
160
+ useEffect(()=>{
161
+ setLocalAnnotations(annotations);
162
+ }, [
163
+ annotations
164
+ ]);
165
+ useEffect(()=>{
166
+ if (!isEdit) setSelectedAnnotationIndex(-1);
167
+ }, [
168
+ isEdit
169
+ ]);
170
+ const handleAnnotationPositionChange = useCallback((position)=>{
171
+ setLocalAnnotations((prev)=>{
172
+ if (-1 === selectedAnnotationIndex) return prev;
173
+ const updated = [
174
+ ...prev
175
+ ];
176
+ updated[selectedAnnotationIndex] = {
177
+ ...updated[selectedAnnotationIndex],
178
+ position
179
+ };
180
+ return updated;
181
+ });
182
+ }, [
183
+ selectedAnnotationIndex
184
+ ]);
185
+ const handleSave = useCallback(()=>{
186
+ const saveAndClose = async ()=>{
187
+ await onSaveAnnotations(localAnnotations);
188
+ setIsEdit(false);
189
+ setSelectedAnnotationIndex(-1);
190
+ };
191
+ saveAndClose();
192
+ }, [
193
+ onSaveAnnotations,
194
+ localAnnotations
195
+ ]);
196
+ const handleCancel = useCallback(()=>{
197
+ setLocalAnnotations(annotations);
198
+ setIsEdit(false);
199
+ setSelectedAnnotationIndex(-1);
200
+ }, [
201
+ annotations
202
+ ]);
203
+ const handleAddAnnotation = useCallback(()=>{
204
+ const newAnnotation = {
205
+ position: origin,
206
+ title: ''
207
+ };
208
+ setLocalAnnotations((prev)=>[
209
+ ...prev,
210
+ newAnnotation
211
+ ]);
212
+ setSelectedAnnotationIndex(localAnnotations.length);
213
+ }, [
214
+ origin,
215
+ localAnnotations
216
+ ]);
217
+ const handleDeleteAnnotation = useCallback(()=>{
218
+ if (-1 === selectedAnnotationIndex) return;
219
+ setLocalAnnotations((prev)=>prev.filter((_, index)=>index !== selectedAnnotationIndex));
220
+ setSelectedAnnotationIndex(-1);
221
+ }, [
222
+ selectedAnnotationIndex
223
+ ]);
224
+ const handleDeselectAnnotation = useCallback(()=>{
225
+ setSelectedAnnotationIndex(-1);
226
+ }, []);
227
+ const handleAnnotationView = useCallback((annotation, annotationIndex, screenX, screenY)=>{
228
+ setViewingAnnotation(annotation);
229
+ setViewingAnnotationIndex(annotationIndex);
230
+ setViewedScreenPos(null);
231
+ }, []);
232
+ const handleAnnotationScreenPositionUpdate = useCallback((_index, screenX, screenY, size)=>{
233
+ if (isCurrentlyInXr) return;
234
+ setViewedScreenPos((prev)=>prev && prev.x === screenX && prev.y === screenY && prev.size === size ? prev : {
235
+ x: screenX,
236
+ y: screenY,
237
+ size
238
+ });
239
+ }, [
240
+ isCurrentlyInXr
241
+ ]);
242
+ const handleCloseAnnotation = useCallback(()=>{
243
+ setViewingAnnotation(null);
244
+ setViewingAnnotationIndex(-1);
245
+ setViewedScreenPos(null);
246
+ }, []);
247
+ const isTeleportBlocked = useCallback((inputSource)=>rayHitsInteractiveUi(app, inputSource.getOrigin(), inputSource.getDirection()), [
248
+ app
249
+ ]);
250
+ useEffect(()=>{
251
+ if (!isCurrentlyInXr) handleCloseAnnotation();
252
+ }, [
253
+ isCurrentlyInXr,
254
+ handleCloseAnnotation
255
+ ]);
256
+ const handleAnnotationUpdate = useCallback((updates)=>{
257
+ if (-1 === selectedAnnotationIndex) return;
258
+ setLocalAnnotations((prev)=>{
259
+ const updated = [
260
+ ...prev
261
+ ];
262
+ updated[selectedAnnotationIndex] = {
263
+ ...updated[selectedAnnotationIndex],
264
+ ...updates
265
+ };
266
+ return updated;
267
+ });
268
+ }, [
269
+ selectedAnnotationIndex
270
+ ]);
271
+ const handleImagesChange = useCallback((files)=>handleAnnotationUpdate({
272
+ images: files
273
+ }), [
274
+ handleAnnotationUpdate
275
+ ]);
276
+ const canSave = useMemo(()=>localAnnotations.every((annotation)=>annotation.title && '' !== annotation.title.trim()), [
277
+ localAnnotations
278
+ ]);
279
+ const splatModel = useMemo(()=>/*#__PURE__*/ jsx(SplatModel, {
280
+ ...splatModelProps,
281
+ splatSrc: splatSrc,
282
+ splatFormat: splatFormat,
283
+ rotation: [
284
+ -180,
285
+ 0,
286
+ 0
287
+ ],
288
+ scaleFactor: scaleFactor,
289
+ revealRain: isHighPerformance
290
+ }, "splat"), [
291
+ isHighPerformance,
292
+ splatSrc,
293
+ splatFormat,
294
+ scaleFactor,
295
+ splatModelProps
296
+ ]);
297
+ return /*#__PURE__*/ jsxs(CameraEntityContext.Provider, {
298
+ value: activeCamera,
299
+ children: [
300
+ /*#__PURE__*/ jsx(GradientSky, {
301
+ topColor: skyColor || '#FFFFFF',
302
+ horizonColor: skyColor || '#EAF8FF',
303
+ groundColor: groundColor || '#C3BDB7'
304
+ }),
305
+ /*#__PURE__*/ jsxs(Entity, {
306
+ name: "camera-root",
307
+ ref: setCameraRoot,
308
+ children: [
309
+ /*#__PURE__*/ jsx(Entity, {
310
+ name: "camera",
311
+ ref: setCameraEntity,
312
+ children: camera
313
+ }),
314
+ !isCurrentlyInXr && /*#__PURE__*/ jsx(Script, {
315
+ script: WalkthroughCamera,
316
+ boundsCenter: sceneBoundsCenter,
317
+ boundsRadius: sceneBoundsRadius,
318
+ enableFly: !isTextFieldFocused,
319
+ averageCameraHeight: averageCameraHeight
320
+ }),
321
+ /*#__PURE__*/ jsx(XrExitButton, {
322
+ onClose: onXrClose
323
+ }),
324
+ /*#__PURE__*/ jsx(Script, {
325
+ script: XrControllers,
326
+ enabled: !isEdit
327
+ }),
328
+ /*#__PURE__*/ jsx(XrAnnotationInteraction, {
329
+ onDismiss: handleCloseAnnotation
330
+ }),
331
+ /*#__PURE__*/ jsx(XrPointerRay, {}),
332
+ isCurrentlyInVr && viewingAnnotation && /*#__PURE__*/ jsx(VrAnnotationPanel, {
333
+ annotation: viewingAnnotation,
334
+ annotationIndex: viewingAnnotationIndex
335
+ }, viewingAnnotationIndex),
336
+ /*#__PURE__*/ jsx(XrGazeDwell, {
337
+ activeIndex: viewingAnnotationIndex
338
+ }),
339
+ /*#__PURE__*/ jsx(Script, {
340
+ script: XrStartPose,
341
+ targetX: cameraPosition[0],
342
+ targetZ: cameraPosition[2],
343
+ focusX: origin[0],
344
+ focusZ: origin[2]
345
+ }),
346
+ /*#__PURE__*/ jsx(Script, {
347
+ script: TfXrNavigation,
348
+ enabled: !isEdit,
349
+ enableTeleport: !isCurrentlyInAr && !viewingAnnotation,
350
+ enableSnapVertical: false,
351
+ isTeleportBlocked: isTeleportBlocked
352
+ }),
353
+ !isCurrentlyInXr && /*#__PURE__*/ jsx(Script, {
354
+ script: AutoRotator,
355
+ enabled: !isEdit && autoRotate && !viewingAnnotation,
356
+ startDelay: 0.5,
357
+ restartDelay: 3,
358
+ startFadeInTime: 0.5
359
+ })
360
+ ]
361
+ }),
362
+ /*#__PURE__*/ jsxs(Entity, {
363
+ name: "content-root",
364
+ children: [
365
+ splatModel,
366
+ sceneBounds?.m !== void 0 && 3 === groundPlane.length && /*#__PURE__*/ jsx(BoundaryRing, {
367
+ center: sceneBoundsCenter,
368
+ radius: sceneBoundsRadius,
369
+ groundPlane: groundPlane
370
+ }),
371
+ localAnnotations.length > 0 && /*#__PURE__*/ jsxs(Entity, {
372
+ name: "annotations-root",
373
+ children: [
374
+ /*#__PURE__*/ jsx(Script, {
375
+ script: TfAnnotationManager,
376
+ enabled: true,
377
+ hotspotSize: 30,
378
+ maxWorldSize: MAX_HOTSPOT_WORLD_SIZE,
379
+ opacity: 1,
380
+ hotspotColor: new Color().fromString(theme.palette.TwClrIcnBrand),
381
+ hoverColor: new Color().fromString('#ffffff'),
382
+ hotspotBackgroundColor: theme.palette.TwClrBaseWhite
383
+ }),
384
+ localAnnotations.map((annotation, index)=>/*#__PURE__*/ jsx(Annotation, {
385
+ ...annotation,
386
+ index: index,
387
+ visible: showAnnotations,
388
+ isEdit: isEdit,
389
+ isSelected: selectedAnnotationIndex === index,
390
+ isViewed: viewingAnnotationIndex === index,
391
+ onSelect: ()=>setSelectedAnnotationIndex(index),
392
+ onPositionChange: handleAnnotationPositionChange,
393
+ onView: (anno, screenX, screenY)=>handleAnnotationView(anno, index, screenX, screenY),
394
+ onScreenPositionUpdate: handleAnnotationScreenPositionUpdate
395
+ }, `annotation-${index}`))
396
+ ]
397
+ })
398
+ ]
399
+ }),
400
+ isCurrentlyInXr && sceneBoundsRadius > 0 && /*#__PURE__*/ jsx(BoundaryWall, {
401
+ center: sceneBoundsCenter,
402
+ radius: sceneBoundsRadius + WALL_INSET,
403
+ groundPlane: groundPlane,
404
+ baseY: 0
405
+ }),
406
+ /*#__PURE__*/ jsx(SplatControls, {
407
+ defaultCameraFocus: origin,
408
+ defaultCameraPosition: cameraPosition,
409
+ showAnnotations: showAnnotations,
410
+ onToggleAnnotations: setShowAnnotations,
411
+ autoRotate: autoRotate,
412
+ onToggleAutoRotate: setAutoRotate,
413
+ isEdit: isEdit,
414
+ onToggleEdit: setIsEdit,
415
+ onSave: handleSave,
416
+ onCancel: handleCancel,
417
+ onAddAnnotation: handleAddAnnotation,
418
+ onDeleteAnnotation: handleDeleteAnnotation,
419
+ onDeselectAnnotation: handleDeselectAnnotation,
420
+ hasSelectedAnnotation: selectedAnnotationIndex >= 0,
421
+ selectedAnnotation: selectedAnnotationIndex >= 0 ? localAnnotations[selectedAnnotationIndex] : null,
422
+ selectedAnnotationIndex: selectedAnnotationIndex,
423
+ onAnnotationUpdate: handleAnnotationUpdate,
424
+ onImagesChange: handleImagesChange,
425
+ maxImagesPerAnnotation: maxImagesPerAnnotation,
426
+ onTextFieldFocus: setIsTextFieldFocused,
427
+ canSave: canSave,
428
+ editable: editable,
429
+ isFullScreen: isFullScreen,
430
+ onToggleFullScreen: onToggleFullScreen,
431
+ isFreeFly: isFreeFly,
432
+ onToggleFreeFly: handleToggleFreeFly,
433
+ showFreeFly: showFreeFly,
434
+ onError: reportXrError
435
+ }),
436
+ /*#__PURE__*/ jsx(AnnotationPanel, {
437
+ annotation: viewingAnnotation,
438
+ hotspotPosition: viewedScreenPos,
439
+ onClose: handleCloseAnnotation
440
+ })
441
+ ]
278
442
  });
279
- }, [isCurrentlyInXr]);
280
- const handleCloseAnnotation = useCallback(() => {
281
- setViewingAnnotation(null);
282
- setViewingAnnotationIndex(-1);
283
- setViewedScreenPos(null);
284
- }, []);
285
- const isTeleportBlocked = useCallback(inputSource => rayHitsInteractiveUi(app, inputSource.getOrigin(), inputSource.getDirection()), [app]);
286
- useEffect(() => {
287
- if (!isCurrentlyInXr) {
288
- handleCloseAnnotation();
289
- }
290
- }, [isCurrentlyInXr, handleCloseAnnotation]);
291
- const handleAnnotationUpdate = useCallback(updates => {
292
- if (selectedAnnotationIndex === -1) {
293
- return;
294
- }
295
- setLocalAnnotations(prev => {
296
- const updated = [...prev];
297
- updated[selectedAnnotationIndex] = {
298
- ...updated[selectedAnnotationIndex],
299
- ...updates
300
- };
301
- return updated;
302
- });
303
- }, [selectedAnnotationIndex]);
304
- const handleImagesChange = useCallback(files => handleAnnotationUpdate({
305
- images: files
306
- }), [handleAnnotationUpdate]);
307
- const canSave = useMemo(() => localAnnotations.every(annotation => annotation.title && annotation.title.trim() !== ''), [localAnnotations]);
308
- const splatModel = useMemo(() => /*#__PURE__*/jsx(SplatModel, {
309
- ...splatModelProps,
310
- splatSrc: splatSrc,
311
- splatFormat: splatFormat,
312
- rotation: [-180, 0, 0],
313
- scaleFactor: scaleFactor,
314
- revealRain: isHighPerformance
315
- }, 'splat'), [isHighPerformance, splatSrc, splatFormat, scaleFactor, splatModelProps]);
316
- return /*#__PURE__*/jsxs(CameraEntityContext.Provider, {
317
- value: activeCamera,
318
- children: [/*#__PURE__*/jsx(GradientSky, {
319
- topColor: skyColor || '#FFFFFF',
320
- horizonColor: skyColor || '#EAF8FF',
321
- groundColor: groundColor || '#C3BDB7'
322
- }), /*#__PURE__*/jsxs(Entity, {
323
- name: "camera-root",
324
- ref: setCameraRoot,
325
- children: [/*#__PURE__*/jsx(Entity, {
326
- name: "camera",
327
- ref: setCameraEntity,
328
- children: camera
329
- }), !isCurrentlyInXr && /*#__PURE__*/jsx(Script, {
330
- script: WalkthroughCamera,
331
- boundsCenter: sceneBoundsCenter,
332
- boundsRadius: sceneBoundsRadius,
333
- enableFly: !isTextFieldFocused,
334
- averageCameraHeight: averageCameraHeight
335
- }), /*#__PURE__*/jsx(XrExitButton, {
336
- onClose: onXrClose
337
- }), /*#__PURE__*/jsx(Script, {
338
- script: XrControllers,
339
- enabled: !isEdit
340
- }), /*#__PURE__*/jsx(XrAnnotationInteraction, {
341
- onDismiss: handleCloseAnnotation
342
- }), /*#__PURE__*/jsx(XrPointerRay, {}), isCurrentlyInVr && viewingAnnotation && /*#__PURE__*/jsx(VrAnnotationPanel, {
343
- annotation: viewingAnnotation,
344
- annotationIndex: viewingAnnotationIndex
345
- }, viewingAnnotationIndex), /*#__PURE__*/jsx(XrGazeDwell, {
346
- activeIndex: viewingAnnotationIndex
347
- }), /*#__PURE__*/jsx(Script, {
348
- script: XrStartPose,
349
- targetX: cameraPosition[0],
350
- targetZ: cameraPosition[2],
351
- focusX: origin[0],
352
- focusZ: origin[2]
353
- }), /*#__PURE__*/jsx(Script, {
354
- script: TfXrNavigation,
355
- enabled: !isEdit,
356
- enableTeleport: !isCurrentlyInAr && !viewingAnnotation,
357
- enableSnapVertical: false,
358
- isTeleportBlocked: isTeleportBlocked
359
- }), !isCurrentlyInXr && /*#__PURE__*/jsx(Script, {
360
- script: AutoRotator,
361
- enabled: !isEdit && autoRotate && !viewingAnnotation,
362
- startDelay: 0.5,
363
- restartDelay: 3,
364
- startFadeInTime: 0.5
365
- })]
366
- }), /*#__PURE__*/jsxs(Entity, {
367
- name: "content-root",
368
- children: [splatModel, sceneBounds?.m !== undefined && groundPlane.length === 3 && /*#__PURE__*/jsx(BoundaryRing, {
369
- center: sceneBoundsCenter,
370
- radius: sceneBoundsRadius,
371
- groundPlane: groundPlane
372
- }), localAnnotations.length > 0 && /*#__PURE__*/jsxs(Entity, {
373
- name: "annotations-root",
374
- children: [/*#__PURE__*/jsx(Script, {
375
- script: TfAnnotationManager,
376
- enabled: true,
377
- hotspotSize: 30,
378
- maxWorldSize: MAX_HOTSPOT_WORLD_SIZE,
379
- opacity: 1,
380
- hotspotColor: new Color().fromString(theme.palette.TwClrIcnBrand),
381
- hoverColor: new Color().fromString('#ffffff'),
382
- hotspotBackgroundColor: theme.palette.TwClrBaseWhite
383
- }), localAnnotations.map((annotation, index) => /*#__PURE__*/jsx(Annotation, {
384
- ...annotation,
385
- index: index,
386
- visible: showAnnotations,
387
- isEdit: isEdit,
388
- isSelected: selectedAnnotationIndex === index,
389
- isViewed: viewingAnnotationIndex === index,
390
- onSelect: () => setSelectedAnnotationIndex(index),
391
- onPositionChange: handleAnnotationPositionChange,
392
- onView: (anno, screenX, screenY) => handleAnnotationView(anno, index, screenX, screenY),
393
- onScreenPositionUpdate: handleAnnotationScreenPositionUpdate
394
- }, `annotation-${index}`))]
395
- })]
396
- }), isCurrentlyInXr && sceneBoundsRadius > 0 && /*#__PURE__*/jsx(BoundaryWall, {
397
- center: sceneBoundsCenter,
398
- radius: sceneBoundsRadius + WALL_INSET,
399
- groundPlane: groundPlane,
400
- baseY: 0
401
- }), /*#__PURE__*/jsx(SplatControls, {
402
- defaultCameraFocus: origin,
403
- defaultCameraPosition: cameraPosition,
404
- showAnnotations: showAnnotations,
405
- onToggleAnnotations: setShowAnnotations,
406
- autoRotate: autoRotate,
407
- onToggleAutoRotate: setAutoRotate,
408
- isEdit: isEdit,
409
- onToggleEdit: setIsEdit,
410
- onSave: handleSave,
411
- onCancel: handleCancel,
412
- onAddAnnotation: handleAddAnnotation,
413
- onDeleteAnnotation: handleDeleteAnnotation,
414
- onDeselectAnnotation: handleDeselectAnnotation,
415
- hasSelectedAnnotation: selectedAnnotationIndex >= 0,
416
- selectedAnnotation: selectedAnnotationIndex >= 0 ? localAnnotations[selectedAnnotationIndex] : null,
417
- selectedAnnotationIndex: selectedAnnotationIndex,
418
- onAnnotationUpdate: handleAnnotationUpdate,
419
- onImagesChange: handleImagesChange,
420
- maxImagesPerAnnotation: maxImagesPerAnnotation,
421
- onTextFieldFocus: setIsTextFieldFocused,
422
- canSave: canSave,
423
- editable: editable,
424
- isFullScreen: isFullScreen,
425
- onToggleFullScreen: onToggleFullScreen,
426
- isFreeFly: isFreeFly,
427
- onToggleFreeFly: handleToggleFreeFly,
428
- showFreeFly: showFreeFly,
429
- onError: reportXrError
430
- }), /*#__PURE__*/jsx(AnnotationPanel, {
431
- annotation: viewingAnnotation,
432
- hotspotPosition: viewedScreenPos,
433
- onClose: handleCloseAnnotation
434
- })]
435
- });
436
443
  };
437
-
438
- export { VirtualWalkthroughViewer as default };
444
+ const VirtualWalkthrough_VirtualWalkthroughViewer = VirtualWalkthroughViewer;
445
+ export default VirtualWalkthrough_VirtualWalkthroughViewer;