@terraware/web-components 5.0.27-rc.0 → 5.0.27

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 (295) hide show
  1. package/components/AntSwitch/index.js +22 -19
  2. package/components/Autocomplete/Autocomplete.js +130 -106
  3. package/components/Badge/index.js +29 -28
  4. package/components/BusySpinner/index.js +45 -40
  5. package/components/Button/Button.js +47 -41
  6. package/components/Checkbox.js +63 -64
  7. package/components/Confirm/index.js +83 -74
  8. package/components/DatePicker/DatePicker.js +141 -138
  9. package/components/DialogBox/DialogBox.js +118 -111
  10. package/components/Divisor.js +18 -18
  11. package/components/Dropdown.js +94 -66
  12. package/components/EditableTable/index.js +271 -211
  13. package/components/ErrorBox/ErrorBox.js +49 -47
  14. package/components/FileChooser/index.js +135 -117
  15. package/components/FormBottomBar/index.js +84 -75
  16. package/components/Icon/Icon.js +20 -12
  17. package/components/Icon/icons/index.js +256 -256
  18. package/components/IconTooltip/index.js +60 -49
  19. package/components/Map/MapBox.js +452 -545
  20. package/components/Map/MapContainer.js +29 -25
  21. package/components/Map/MapDateSliderControl.js +64 -64
  22. package/components/Map/MapDrawer.js +47 -41
  23. package/components/Map/MapLegend.js +172 -176
  24. package/components/Map/MapViewStyleControl.js +63 -59
  25. package/components/Map/ReactMapboxWrapper.js +2 -3
  26. package/components/Map/index.js +180 -161
  27. package/components/Map/types.js +17 -12
  28. package/components/Map/useMaintainLayerOrder.js +26 -16
  29. package/components/Markdown/index.js +26 -25
  30. package/components/Message/Message.js +76 -73
  31. package/components/MultiSelect/index.js +124 -112
  32. package/components/Navbar/NavFooter.js +13 -9
  33. package/components/Navbar/NavItem.js +76 -70
  34. package/components/Navbar/NavSection.js +19 -17
  35. package/components/Navbar/Navbar.js +46 -39
  36. package/components/Navbar/SubNavbar.js +13 -9
  37. package/components/Note.js +22 -18
  38. package/components/OverlayModal/OverlayModal.js +63 -56
  39. package/components/PageForm/index.js +41 -33
  40. package/components/PhotoChooser/index.js +173 -165
  41. package/components/PhotosCarousel/PhotoSlide.js +35 -32
  42. package/components/PhotosCarousel/index.js +85 -80
  43. package/components/PhotosCarousel/usePhotosCarousel.js +76 -69
  44. package/components/Pill/index.js +45 -41
  45. package/components/PillList/index.js +24 -17
  46. package/components/PlacementWrapper/index.js +59 -38
  47. package/components/PopoverMenu/Popover.js +85 -68
  48. package/components/PopoverMenu/index.js +56 -51
  49. package/components/PopoverMultiSelect/index.js +59 -52
  50. package/components/ProgressCircle/ProgressCircle.js +32 -28
  51. package/components/RadioButton.js +19 -17
  52. package/components/Select/Select.js +15 -13
  53. package/components/Select/SelectT.js +250 -235
  54. package/components/Separator/index.js +17 -14
  55. package/components/Size.js +1 -0
  56. package/components/Slider/index.js +56 -43
  57. package/components/SummaryBox.js +72 -70
  58. package/components/Tabs/index.js +135 -133
  59. package/components/TextTruncated/index.js +130 -117
  60. package/components/Textfield/Textfield.js +190 -158
  61. package/components/Textfield/TruncatedTextArea.js +84 -70
  62. package/components/TimelineSlider/TimelineMarker.js +30 -25
  63. package/components/TimelineSlider/TimelineRail.js +11 -8
  64. package/components/TimelineSlider/index.js +66 -64
  65. package/components/TimelineSliderV2/ClusterBadge.js +29 -25
  66. package/components/TimelineSliderV2/TimelineDot.js +35 -31
  67. package/components/TimelineSliderV2/TimelineRail.js +11 -8
  68. package/components/TimelineSliderV2/index.js +103 -121
  69. package/components/TimelineSliderV2/layout.js +147 -124
  70. package/components/TimelineSliderV2/types.js +1 -0
  71. package/components/Tooltip/Tooltip.js +56 -47
  72. package/components/ViewPhotosDialog/index.js +35 -28
  73. package/components/VirtualWalkthrough/Annotation.js +207 -163
  74. package/components/VirtualWalkthrough/AnnotationEditPane.js +184 -198
  75. package/components/VirtualWalkthrough/AnnotationPanel.js +199 -187
  76. package/components/VirtualWalkthrough/Application.js +34 -31
  77. package/components/VirtualWalkthrough/AutoRotator.js +223 -85
  78. package/components/VirtualWalkthrough/BlockingSpinner.js +28 -26
  79. package/components/VirtualWalkthrough/BoundaryRing.js +34 -30
  80. package/components/VirtualWalkthrough/BoundaryWall.js +36 -32
  81. package/components/VirtualWalkthrough/CameraInfo.js +89 -100
  82. package/components/VirtualWalkthrough/ControlsInfoPane.js +195 -254
  83. package/components/VirtualWalkthrough/GradientSky.js +73 -72
  84. package/components/VirtualWalkthrough/SplatControls.js +221 -209
  85. package/components/VirtualWalkthrough/SplatCrop.js +20 -21
  86. package/components/VirtualWalkthrough/SplatFadeCrop.js +20 -21
  87. package/components/VirtualWalkthrough/SplatModel.js +85 -65
  88. package/components/VirtualWalkthrough/SplatRevealRain.js +46 -41
  89. package/components/VirtualWalkthrough/TfAnnotationManager.js +379 -197
  90. package/components/VirtualWalkthrough/TfXrNavigation.js +162 -73
  91. package/components/VirtualWalkthrough/VirtualWalkthroughViewer.js +431 -438
  92. package/components/VirtualWalkthrough/VrAnnotationPanel.js +22 -18
  93. package/components/VirtualWalkthrough/XrAnnotationInteraction.js +17 -14
  94. package/components/VirtualWalkthrough/XrExitButton.js +17 -14
  95. package/components/VirtualWalkthrough/XrGazeDwell.js +17 -14
  96. package/components/VirtualWalkthrough/XrPointerRay.js +17 -14
  97. package/components/VirtualWalkthrough/XrStartPose.js +121 -67
  98. package/components/VirtualWalkthrough/boundary-ring.js +117 -87
  99. package/components/VirtualWalkthrough/boundary-wall.js +258 -175
  100. package/components/VirtualWalkthrough/camera-adoption.js +64 -18
  101. package/components/VirtualWalkthrough/groundPlane.js +47 -32
  102. package/components/VirtualWalkthrough/gsplat-fade-crop-effect.js +35 -35
  103. package/components/VirtualWalkthrough/splatFormat.js +47 -13
  104. package/components/VirtualWalkthrough/useAdoptedCamera.js +44 -23
  105. package/components/VirtualWalkthrough/useRestartOnVr.js +37 -26
  106. package/components/VirtualWalkthrough/useXrRenderTuning.js +54 -33
  107. package/components/VirtualWalkthrough/vr-annotation-panel-layout.js +99 -67
  108. package/components/VirtualWalkthrough/vr-annotation-panel.js +433 -403
  109. package/components/VirtualWalkthrough/vr-annotation-scroll.js +28 -10
  110. package/components/VirtualWalkthrough/walkthrough-camera.js +329 -204
  111. package/components/VirtualWalkthrough/xr-annotation-candidate-buffer.js +80 -39
  112. package/components/VirtualWalkthrough/xr-annotation-candidates.js +18 -6
  113. package/components/VirtualWalkthrough/xr-annotation-interaction.js +56 -31
  114. package/components/VirtualWalkthrough/xr-annotation-targeting.js +38 -22
  115. package/components/VirtualWalkthrough/xr-button-arming.js +17 -7
  116. package/components/VirtualWalkthrough/xr-button-hold.js +36 -22
  117. package/components/VirtualWalkthrough/xr-exit-button-mask.js +36 -22
  118. package/components/VirtualWalkthrough/xr-exit-button.js +207 -148
  119. package/components/VirtualWalkthrough/xr-face-buttons.js +29 -19
  120. package/components/VirtualWalkthrough/xr-gaze-dwell-state.js +34 -23
  121. package/components/VirtualWalkthrough/xr-gaze-dwell.js +144 -107
  122. package/components/VirtualWalkthrough/xr-interactive-ui.js +24 -12
  123. package/components/VirtualWalkthrough/xr-pointer-ray.js +20 -13
  124. package/components/VirtualWalkthrough/xr-progress-pie-material.js +88 -117
  125. package/components/VirtualWalkthrough/xr-progress-pie.js +10 -1
  126. package/components/VirtualWalkthrough/xr-ray-quad.js +30 -16
  127. package/components/VirtualWalkthrough/xr-render-tuning.js +48 -17
  128. package/components/VirtualWalkthrough/xr-scene-bounds.js +37 -21
  129. package/components/VirtualWalkthrough/xr-start-pose.js +73 -27
  130. package/components/VirtualWalkthrough/xr-teleport-gesture.js +42 -16
  131. package/components/svg/BlobbyGrayIconImage.js +39 -41
  132. package/components/svg/BlobbyGrayIconImport.js +39 -41
  133. package/components/svg/BlobbyGrayIconUploadToTheCloud.js +39 -41
  134. package/components/svg/BlobbyIconCloudChecked.js +164 -202
  135. package/components/svg/BlobbyIconExportOrUploadPhoto.js +164 -202
  136. package/components/svg/BlobbyIconFolder.js +164 -202
  137. package/components/svg/BlobbyIconGraphReport.js +164 -202
  138. package/components/svg/BlobbyIconHappy.js +164 -202
  139. package/components/svg/BlobbyIconHeartMonitor.js +164 -202
  140. package/components/svg/BlobbyIconLeaf.js +164 -202
  141. package/components/svg/BlobbyIconLibrary.js +164 -202
  142. package/components/svg/BlobbyIconNursery.js +166 -204
  143. package/components/svg/BlobbyIconOrganization.js +164 -202
  144. package/components/svg/BlobbyIconParchment.js +164 -202
  145. package/components/svg/BlobbyIconPeople.js +164 -202
  146. package/components/svg/BlobbyIconSeedBank.js +164 -202
  147. package/components/svg/BlobbyIconSeedling.js +164 -202
  148. package/components/svg/BlobbyIconSeeds.js +164 -202
  149. package/components/svg/BlobbyIconSite.js +167 -206
  150. package/components/svg/BlobbyIconSparkles.js +164 -202
  151. package/components/svg/BlobbyIconWrench.js +164 -202
  152. package/components/svg/Bug.js +21 -19
  153. package/components/svg/Calendar.js +21 -19
  154. package/components/svg/CaretDown.js +21 -19
  155. package/components/svg/CaretLeft.js +21 -19
  156. package/components/svg/CaretRight.js +21 -19
  157. package/components/svg/CaretUp.js +21 -19
  158. package/components/svg/ChevronDown.js +21 -19
  159. package/components/svg/ChevronUp.js +21 -19
  160. package/components/svg/Close.js +21 -19
  161. package/components/svg/Critical.js +21 -19
  162. package/components/svg/Edit.js +164 -202
  163. package/components/svg/Error.js +21 -19
  164. package/components/svg/Filter.js +21 -19
  165. package/components/svg/Folder.js +21 -19
  166. package/components/svg/Help.js +21 -19
  167. package/components/svg/Home.js +21 -19
  168. package/components/svg/IconAdd.js +21 -19
  169. package/components/svg/IconArrowRight.js +23 -21
  170. package/components/svg/IconBusinessNetwork.js +21 -19
  171. package/components/svg/IconCalendar.js +21 -19
  172. package/components/svg/IconCancel.js +21 -19
  173. package/components/svg/IconChargingBattery.js +21 -19
  174. package/components/svg/IconChecklist.js +23 -21
  175. package/components/svg/IconCheckmark.js +21 -19
  176. package/components/svg/IconCoinInHand.js +21 -19
  177. package/components/svg/IconColumns.js +21 -19
  178. package/components/svg/IconComment.js +22 -20
  179. package/components/svg/IconDashboard.js +21 -19
  180. package/components/svg/IconDataMigration.js +21 -19
  181. package/components/svg/IconDocument.js +23 -21
  182. package/components/svg/IconDownloadFromTheCloud.js +23 -21
  183. package/components/svg/IconEdit.js +23 -21
  184. package/components/svg/IconExpand.js +23 -21
  185. package/components/svg/IconExport.js +21 -19
  186. package/components/svg/IconExternalLink.js +21 -19
  187. package/components/svg/IconEye.js +21 -19
  188. package/components/svg/IconEyeOff.js +21 -19
  189. package/components/svg/IconFile.js +21 -19
  190. package/components/svg/IconFolder.js +21 -19
  191. package/components/svg/IconFullScreen.js +22 -20
  192. package/components/svg/IconFutures.js +21 -19
  193. package/components/svg/IconGraphReport.js +21 -19
  194. package/components/svg/IconGrid.js +21 -19
  195. package/components/svg/IconHeartMonitor.js +21 -19
  196. package/components/svg/IconHelp.js +23 -21
  197. package/components/svg/IconHistory.js +21 -19
  198. package/components/svg/IconImport.js +21 -19
  199. package/components/svg/IconIndex.js +21 -19
  200. package/components/svg/IconLayers.js +21 -19
  201. package/components/svg/IconLibrary.js +22 -20
  202. package/components/svg/IconList.js +21 -19
  203. package/components/svg/IconLivePlant.js +21 -19
  204. package/components/svg/IconLocations.js +21 -19
  205. package/components/svg/IconMail.js +21 -19
  206. package/components/svg/IconManager.js +21 -19
  207. package/components/svg/IconMap.js +21 -19
  208. package/components/svg/IconMarker.js +21 -19
  209. package/components/svg/IconMenu.js +21 -19
  210. package/components/svg/IconMenuHorizontal.js +21 -19
  211. package/components/svg/IconModule.js +21 -19
  212. package/components/svg/IconMyLocation.js +21 -19
  213. package/components/svg/IconNote.js +23 -21
  214. package/components/svg/IconNursery.js +23 -21
  215. package/components/svg/IconOrg.js +21 -19
  216. package/components/svg/IconParchment.js +21 -19
  217. package/components/svg/IconPhoto.js +21 -19
  218. package/components/svg/IconPlantsFilled.js +21 -19
  219. package/components/svg/IconRedo.js +21 -19
  220. package/components/svg/IconRestorationSite.js +21 -19
  221. package/components/svg/IconSeedBank.js +21 -19
  222. package/components/svg/IconSeedling.js +21 -19
  223. package/components/svg/IconSettings.js +21 -19
  224. package/components/svg/IconSlice.js +21 -19
  225. package/components/svg/IconSubmit.js +21 -19
  226. package/components/svg/IconSubtract.js +23 -21
  227. package/components/svg/IconSynced.js +21 -19
  228. package/components/svg/IconTrashCan.js +21 -19
  229. package/components/svg/IconTreasureMap.js +21 -19
  230. package/components/svg/IconUnavailable.js +21 -19
  231. package/components/svg/IconUndo.js +21 -19
  232. package/components/svg/IconVariable.js +21 -19
  233. package/components/svg/IconVideo.js +31 -30
  234. package/components/svg/IconWifi.js +21 -19
  235. package/components/svg/Info.js +21 -19
  236. package/components/svg/Key.js +21 -19
  237. package/components/svg/Leaf.js +21 -19
  238. package/components/svg/Lock.js +21 -19
  239. package/components/svg/Logo.js +43 -48
  240. package/components/svg/MenuVertical.js +21 -19
  241. package/components/svg/Notification.js +21 -19
  242. package/components/svg/Person.js +21 -19
  243. package/components/svg/Plus.js +21 -19
  244. package/components/svg/RestorationSite.js +21 -19
  245. package/components/svg/Search.js +21 -19
  246. package/components/svg/Seeds.js +21 -19
  247. package/components/svg/Site.js +21 -19
  248. package/components/svg/Sparkles.js +21 -19
  249. package/components/svg/Species.js +21 -19
  250. package/components/svg/Species2.js +164 -202
  251. package/components/svg/Spinner.js +48 -54
  252. package/components/svg/Star.js +21 -19
  253. package/components/svg/Success.js +21 -19
  254. package/components/svg/SuccessFilled.js +21 -19
  255. package/components/svg/TerrawareLogoDesktop.js +49 -55
  256. package/components/svg/TerrawareLogoMobile.js +26 -25
  257. package/components/svg/Touchscreen.js +21 -19
  258. package/components/svg/UploadCloud.js +164 -202
  259. package/components/svg/Warning.js +21 -19
  260. package/components/svg/WelcomeClipboard.js +133 -156
  261. package/components/svg/index.js +129 -129
  262. package/components/table/EnhancedTableToolbar.js +74 -68
  263. package/components/table/EnhancedTableToolbarV2.js +41 -31
  264. package/components/table/TableCellRenderer.js +231 -196
  265. package/components/table/TableHeader.js +73 -71
  266. package/components/table/TableHeaderItem.js +102 -97
  267. package/components/table/density.js +19 -18
  268. package/components/table/index.js +369 -350
  269. package/components/table/sort.js +52 -27
  270. package/components/table/types.js +1 -0
  271. package/components/types/index.js +1 -0
  272. package/hooks/cameraEntityContext.js +13 -2
  273. package/hooks/useBoolean.js +13 -17
  274. package/hooks/useCameraPosition.js +56 -56
  275. package/hooks/useDevicePerformance.js +17 -17
  276. package/hooks/useXr.js +87 -85
  277. package/index.js +58 -58
  278. package/package.json +1 -1
  279. package/setupTests.js +4 -0
  280. package/strings/export.js +170 -111
  281. package/strings/index.js +54 -25
  282. package/strings/locales.js +41 -21
  283. package/strings/strings-en.js +51 -49
  284. package/strings/strings-es.js +51 -49
  285. package/strings/strings-fr.js +51 -49
  286. package/strings/strings-gx.js +51 -49
  287. package/style-dictionary-dist/TerrawareTheme.js +186 -186
  288. package/theme.js +76 -74
  289. package/utils/color.js +15 -8
  290. package/utils/date.js +108 -42
  291. package/utils/index.js +4 -4
  292. package/utils/preventDefaultEvent.js +3 -3
  293. package/utils/text.js +11 -11
  294. package/utils/useDeviceInfo.js +79 -42
  295. package/virtualWalkthrough.js +23 -23
@@ -1,30 +1,37 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { useEffect, useState } from "react";
3
- import DialogBox from "../DialogBox/DialogBox.js";
4
- import PhotosCarousel from "../PhotosCarousel/index.js";
1
+ import { useState, useEffect } from 'react';
2
+ import DialogBox from '../DialogBox/DialogBox.js';
3
+ import PhotosCarousel from '../PhotosCarousel/index.js';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
5
6
  function ViewPhotosDialog(props) {
6
- const { onClose, open, photos, initialSelectedSlide, title, numbered, dots } = props;
7
- const [selectedSlide, setSelectedSlide] = useState(initialSelectedSlide);
8
- useEffect(()=>{
9
- setSelectedSlide(initialSelectedSlide);
10
- }, [
11
- initialSelectedSlide,
12
- open
13
- ]);
14
- return /*#__PURE__*/ jsx(DialogBox, {
15
- onClose: onClose,
16
- open: open,
17
- title: title,
18
- size: "large",
19
- scrolled: true,
20
- children: /*#__PURE__*/ jsx(PhotosCarousel, {
21
- photos: photos,
22
- selectedSlide: selectedSlide,
23
- onSlideChange: setSelectedSlide,
24
- numbered: numbered,
25
- dots: dots,
26
- showArrows: true
27
- })
28
- });
7
+ const {
8
+ onClose,
9
+ open,
10
+ photos,
11
+ initialSelectedSlide,
12
+ title,
13
+ numbered,
14
+ dots
15
+ } = props;
16
+ const [selectedSlide, setSelectedSlide] = useState(initialSelectedSlide);
17
+ useEffect(() => {
18
+ setSelectedSlide(initialSelectedSlide);
19
+ }, [initialSelectedSlide, open]);
20
+ return /*#__PURE__*/jsx(DialogBox, {
21
+ onClose: onClose,
22
+ open: open,
23
+ title: title,
24
+ size: "large",
25
+ scrolled: true,
26
+ children: /*#__PURE__*/jsx(PhotosCarousel, {
27
+ photos: photos,
28
+ selectedSlide: selectedSlide,
29
+ onSlideChange: setSelectedSlide,
30
+ numbered: numbered,
31
+ dots: dots,
32
+ showArrows: true
33
+ })
34
+ });
29
35
  }
30
- export default ViewPhotosDialog;
36
+
37
+ export { ViewPhotosDialog as default };
@@ -1,166 +1,210 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { useCallback, useContext, useEffect, useMemo, useRef } from "react";
3
- import { Entity } from "@playcanvas/react";
4
- import { Script } from "@playcanvas/react/components";
5
- import { useApp } from "@playcanvas/react/hooks";
6
- import { Gizmo, TranslateGizmo } from "playcanvas";
7
- import { Annotation } from "playcanvas/scripts/esm/annotations.mjs";
8
- import { CameraControls } from "playcanvas/scripts/esm/camera-controls.mjs";
9
- import { CameraEntityContext } from "../../hooks/cameraEntityContext.js";
10
- import { useCameraPosition } from "../../hooks/useCameraPosition.js";
11
- import "./annotation-styles.css";
1
+ import { useContext, useRef, useEffect, useCallback, useMemo } from 'react';
2
+ import { Entity } from '@playcanvas/react';
3
+ import { Script } from '@playcanvas/react/components';
4
+ import { useApp } from '@playcanvas/react/hooks';
5
+ import { Gizmo, TranslateGizmo } from 'playcanvas';
6
+ import { Annotation as Annotation$1 } from 'playcanvas/scripts/esm/annotations.mjs';
7
+ import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs';
8
+ import { CameraEntityContext } from '../../hooks/cameraEntityContext.js';
9
+ import { useCameraPosition } from '../../hooks/useCameraPosition.js';
10
+ import './annotation-styles.css';
11
+ import { jsx } from 'react/jsx-runtime';
12
+
13
+ /**
14
+ * Target normalized-device x coordinate for a clicked annotation. +0.5 places
15
+ * the hotspot three quarters across the screen (25% from the right), leaving room
16
+ * for the annotation panel on the left without covering the hotspot.
17
+ */
12
18
  const VIEW_HORIZONTAL_NDC_BIAS = 0.5;
13
- const Annotation_Annotation = (props)=>{
14
- const { position, cameraPosition, bodyText, imageUrls, icon, title, label, visible = true, isEdit = false, isSelected = false, isViewed = false, onSelect, onPositionChange, onView, onScreenPositionUpdate, index } = props;
15
- const app = useApp();
16
- const walkthroughCamera = useContext(CameraEntityContext);
17
- const { setCamera } = useCameraPosition();
18
- const gizmoRef = useRef(null);
19
- const layerRef = useRef(null);
20
- const isEditRef = useRef(isEdit);
21
- const onSelectRef = useRef(onSelect);
22
- const onViewRef = useRef(onView);
23
- const onScreenPositionUpdateRef = useRef(onScreenPositionUpdate);
24
- const positionRef = useRef(position);
25
- const cameraPositionRef = useRef(cameraPosition);
26
- const annotationForViewRef = useRef({
27
- position,
28
- title,
29
- label,
30
- bodyText,
31
- imageUrls,
32
- cameraPosition
33
- });
34
- useEffect(()=>{
35
- isEditRef.current = isEdit;
36
- onSelectRef.current = onSelect;
37
- onViewRef.current = onView;
38
- onScreenPositionUpdateRef.current = onScreenPositionUpdate;
39
- positionRef.current = position;
40
- cameraPositionRef.current = cameraPosition;
41
- annotationForViewRef.current = {
42
- position,
43
- title,
44
- label,
45
- bodyText,
46
- imageUrls,
47
- cameraPosition
48
- };
49
- }, [
50
- isEdit,
51
- onSelect,
52
- onView,
53
- onScreenPositionUpdate,
54
- position,
55
- cameraPosition,
56
- title,
57
- label,
58
- bodyText,
59
- imageUrls
60
- ]);
61
- const handleClick = useCallback((screenX, screenY)=>{
62
- if (isEditRef.current) onSelectRef.current?.();
63
- else {
64
- setCamera(positionRef.current, cameraPositionRef.current, VIEW_HORIZONTAL_NDC_BIAS);
65
- if (onViewRef.current && void 0 !== screenX && void 0 !== screenY) onViewRef.current(annotationForViewRef.current, screenX, screenY);
19
+ /**
20
+ * A 3D annotation component that displays a hotspot in the scene.
21
+ * When clicked, displays annotation text and moves the camera.
22
+ * In edit mode, shows a translate gizmo when selected.
23
+ *
24
+ * @param props.position - The world position of the annotation
25
+ * @param props.index - The index of the annotation, used as a unique identifier
26
+ * @param props.title - The title displayed in the annotation
27
+ * @param props.bodyText - Optional description displayed in the annotation
28
+ * @param props.label - Optional label displayed on the hotspot
29
+ * @param props.cameraPosition - Optional camera position to move to when clicked. If undefined, camera stays at current position
30
+ * @param props.visible - Optional flag to show/hide the annotation. Defaults to true
31
+ * @param props.isEdit - Optional flag for edit mode. Defaults to false
32
+ * @param props.isSelected - Optional flag indicating if this annotation is selected. Defaults to false
33
+ * @param props.onSelect - Optional callback when annotation is clicked in edit mode
34
+ * @param props.onPositionChange - Optional callback when annotation position changes
35
+ */
36
+ const Annotation = props => {
37
+ const {
38
+ position,
39
+ cameraPosition,
40
+ bodyText,
41
+ imageUrls,
42
+ icon,
43
+ title,
44
+ label,
45
+ visible = true,
46
+ isEdit = false,
47
+ isSelected = false,
48
+ isViewed = false,
49
+ onSelect,
50
+ onPositionChange,
51
+ onView,
52
+ onScreenPositionUpdate,
53
+ index
54
+ } = props;
55
+ const app = useApp();
56
+ const walkthroughCamera = useContext(CameraEntityContext);
57
+ const {
58
+ setCamera
59
+ } = useCameraPosition();
60
+ const gizmoRef = useRef(null);
61
+ const layerRef = useRef(null);
62
+
63
+ // Use refs to always call the latest callback values
64
+ const isEditRef = useRef(isEdit);
65
+ const onSelectRef = useRef(onSelect);
66
+ const onViewRef = useRef(onView);
67
+ const onScreenPositionUpdateRef = useRef(onScreenPositionUpdate);
68
+ const positionRef = useRef(position);
69
+ const cameraPositionRef = useRef(cameraPosition);
70
+ const annotationForViewRef = useRef({
71
+ position,
72
+ title,
73
+ label,
74
+ bodyText,
75
+ imageUrls,
76
+ cameraPosition
77
+ });
78
+ useEffect(() => {
79
+ isEditRef.current = isEdit;
80
+ onSelectRef.current = onSelect;
81
+ onViewRef.current = onView;
82
+ onScreenPositionUpdateRef.current = onScreenPositionUpdate;
83
+ positionRef.current = position;
84
+ cameraPositionRef.current = cameraPosition;
85
+ annotationForViewRef.current = {
86
+ position,
87
+ title,
88
+ label,
89
+ bodyText,
90
+ imageUrls,
91
+ cameraPosition
92
+ };
93
+ }, [isEdit, onSelect, onView, onScreenPositionUpdate, position, cameraPosition, title, label, bodyText, imageUrls]);
94
+
95
+ // Create a stable callback that reads from refs, because this is read from TfAnnotationManager when the annotation is added to the scene
96
+ const handleClick = useCallback((screenX, screenY) => {
97
+ if (isEditRef.current) {
98
+ onSelectRef.current?.();
99
+ } else {
100
+ setCamera(positionRef.current, cameraPositionRef.current, VIEW_HORIZONTAL_NDC_BIAS);
101
+ if (onViewRef.current && screenX !== undefined && screenY !== undefined) {
102
+ onViewRef.current(annotationForViewRef.current, screenX, screenY);
103
+ }
104
+ }
105
+ }, [setCamera]);
106
+
107
+ // VR open path: shows the annotation without moving the camera (roomscale head pose
108
+ // comes from the XR views, so a camera move would be disorienting or a no-op).
109
+ const handleVrOpen = useCallback((screenX, screenY) => {
110
+ if (isEditRef.current) {
111
+ return;
112
+ }
113
+ onViewRef.current?.(annotationForViewRef.current, screenX, screenY);
114
+ }, []);
115
+
116
+ // Stable callback so its identity doesn't churn the underlying script prop each frame.
117
+ const handleScreenPositionUpdate = useCallback((screenX, screenY, size) => {
118
+ onScreenPositionUpdateRef.current?.(index, screenX, screenY, size);
119
+ }, [index]);
120
+ const entityName = useMemo(() => `annotation-${index}`, [index]);
121
+ useEffect(() => {
122
+ const shouldShowGizmo = isEdit && isSelected && visible;
123
+ const cleanupGizmo = () => {
124
+ if (gizmoRef.current) {
125
+ try {
126
+ gizmoRef.current.detach();
127
+ gizmoRef.current.destroy();
128
+ } catch (error) {
129
+ // Ignore cleanup errors
66
130
  }
67
- }, [
68
- setCamera
69
- ]);
70
- const handleVrOpen = useCallback((screenX, screenY)=>{
71
- if (isEditRef.current) return;
72
- onViewRef.current?.(annotationForViewRef.current, screenX, screenY);
73
- }, []);
74
- const handleScreenPositionUpdate = useCallback((screenX, screenY, size)=>{
75
- onScreenPositionUpdateRef.current?.(index, screenX, screenY, size);
76
- }, [
77
- index
78
- ]);
79
- const entityName = useMemo(()=>`annotation-${index}`, [
80
- index
81
- ]);
82
- useEffect(()=>{
83
- const shouldShowGizmo = isEdit && isSelected && visible;
84
- const cleanupGizmo = ()=>{
85
- if (gizmoRef.current) {
86
- try {
87
- gizmoRef.current.detach();
88
- gizmoRef.current.destroy();
89
- } catch (error) {}
90
- gizmoRef.current = null;
91
- }
92
- if (layerRef.current && app.scene?.layers) {
93
- try {
94
- const layer = app.scene.layers.getLayerByName('Gizmo');
95
- if (layer) app.scene.layers.remove(layerRef.current);
96
- } catch (error) {}
97
- layerRef.current = null;
98
- }
99
- };
100
- if (!shouldShowGizmo) return void cleanupGizmo();
101
- const setupGizmo = ()=>{
102
- const annotationEntity = app.root.findByName(entityName);
103
- const cameraComponent = walkthroughCamera?.camera;
104
- const cameraControls = walkthroughCamera?.script?.get(CameraControls.scriptName);
105
- if (!annotationEntity || !cameraComponent) return false;
106
- if (!gizmoRef.current) {
107
- if (!layerRef.current) layerRef.current = Gizmo.createLayer(app);
108
- const gizmo = new TranslateGizmo(cameraComponent, layerRef.current);
109
- gizmo.size = 0.75;
110
- gizmo.snapIncrement = 0.01;
111
- gizmo.coordSpace = 'world';
112
- gizmo.on('transform:start', ()=>{
113
- if (cameraControls) cameraControls.enabled = false;
114
- });
115
- gizmo.on('transform:end', ()=>{
116
- if (cameraControls) cameraControls.enabled = true;
117
- if (onPositionChange) {
118
- const pos = annotationEntity.getPosition();
119
- onPositionChange([
120
- pos.x,
121
- pos.y,
122
- pos.z
123
- ]);
124
- }
125
- });
126
- gizmo.attach([
127
- annotationEntity
128
- ]);
129
- gizmoRef.current = gizmo;
130
- }
131
- return true;
132
- };
133
- const intervalId = setInterval(()=>{
134
- if (setupGizmo()) clearInterval(intervalId);
135
- }, 100);
136
- return ()=>{
137
- clearInterval(intervalId);
138
- cleanupGizmo();
139
- };
140
- }, [
141
- app,
142
- isEdit,
143
- isSelected,
144
- visible,
145
- onPositionChange,
146
- entityName,
147
- walkthroughCamera
148
- ]);
149
- return /*#__PURE__*/ jsx(Entity, {
150
- name: entityName,
151
- position: position,
152
- children: /*#__PURE__*/ jsx(Script, {
153
- script: Annotation,
154
- title: title,
155
- label: label,
156
- icon: icon,
157
- text: bodyText,
158
- enabled: visible,
159
- onClickCallback: handleClick,
160
- onVrOpenCallback: handleVrOpen,
161
- onScreenPositionUpdateCallback: isViewed ? handleScreenPositionUpdate : void 0
162
- })
163
- });
131
+ gizmoRef.current = null;
132
+ }
133
+ if (layerRef.current && app.scene?.layers) {
134
+ try {
135
+ const layer = app.scene.layers.getLayerByName('Gizmo');
136
+ if (layer) {
137
+ app.scene.layers.remove(layerRef.current);
138
+ }
139
+ } catch (error) {
140
+ // Ignore cleanup errors
141
+ }
142
+ layerRef.current = null;
143
+ }
144
+ };
145
+ if (!shouldShowGizmo) {
146
+ cleanupGizmo();
147
+ return;
148
+ }
149
+ const setupGizmo = () => {
150
+ const annotationEntity = app.root.findByName(entityName);
151
+ const cameraComponent = walkthroughCamera?.camera;
152
+ const cameraControls = walkthroughCamera?.script?.get(CameraControls.scriptName);
153
+ if (!annotationEntity || !cameraComponent) {
154
+ return false;
155
+ }
156
+ if (!gizmoRef.current) {
157
+ if (!layerRef.current) {
158
+ layerRef.current = Gizmo.createLayer(app);
159
+ }
160
+ const gizmo = new TranslateGizmo(cameraComponent, layerRef.current);
161
+ gizmo.size = 0.75;
162
+ gizmo.snapIncrement = 0.01;
163
+ gizmo.coordSpace = 'world';
164
+ gizmo.on('transform:start', () => {
165
+ if (cameraControls) {
166
+ cameraControls.enabled = false;
167
+ }
168
+ });
169
+ gizmo.on('transform:end', () => {
170
+ if (cameraControls) {
171
+ cameraControls.enabled = true;
172
+ }
173
+ if (onPositionChange) {
174
+ const pos = annotationEntity.getPosition();
175
+ onPositionChange([pos.x, pos.y, pos.z]);
176
+ }
177
+ });
178
+ gizmo.attach([annotationEntity]);
179
+ gizmoRef.current = gizmo;
180
+ }
181
+ return true;
182
+ };
183
+ const intervalId = setInterval(() => {
184
+ if (setupGizmo()) {
185
+ clearInterval(intervalId);
186
+ }
187
+ }, 100);
188
+ return () => {
189
+ clearInterval(intervalId);
190
+ cleanupGizmo();
191
+ };
192
+ }, [app, isEdit, isSelected, visible, onPositionChange, entityName, walkthroughCamera]);
193
+ return /*#__PURE__*/jsx(Entity, {
194
+ name: entityName,
195
+ position: position,
196
+ children: /*#__PURE__*/jsx(Script, {
197
+ script: Annotation$1,
198
+ title: title,
199
+ label: label,
200
+ icon: icon,
201
+ text: bodyText,
202
+ enabled: visible,
203
+ onClickCallback: handleClick,
204
+ onVrOpenCallback: handleVrOpen,
205
+ onScreenPositionUpdateCallback: isViewed ? handleScreenPositionUpdate : undefined
206
+ })
207
+ });
164
208
  };
165
- const VirtualWalkthrough_Annotation = Annotation_Annotation;
166
- export default VirtualWalkthrough_Annotation;
209
+
210
+ export { Annotation as default };