@terraware/web-components 4.2.19 → 4.2.20

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.
@@ -1 +1 @@
1
- {"version":3,"file":"SplatControls.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/SplatControls.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAA2B,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAmB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAyB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAE/E,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,uBAAuB,CAAC;IAC1C,UAAU,EAAE,iBAAiB,CAAC;IAC9B,kBAAkB,EAAE,yBAAyB,CAAC;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,oBAAoB,CAAC;IAC9B,qBAAqB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,kBAAkB,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC5C,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,kBAAkB,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IAChE,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,QAAA,MAAM,aAAa,GAAI,2dA8BpB,kBAAkB,4CA8NpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"SplatControls.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/SplatControls.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAA2B,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAmB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAyB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAE/E,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,uBAAuB,CAAC;IAC1C,UAAU,EAAE,iBAAiB,CAAC;IAC9B,kBAAkB,EAAE,yBAAyB,CAAC;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,oBAAoB,CAAC;IAC9B,qBAAqB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,kBAAkB,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC5C,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,kBAAkB,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IAChE,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,QAAA,MAAM,aAAa,GAAI,2dA8BpB,kBAAkB,4CAwKpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -1,10 +1,9 @@
1
- import React, { useCallback, useEffect, useRef, useState } from 'react';
1
+ import React, { useCallback, useEffect, useRef } from 'react';
2
2
  import { Fullscreen, FullscreenExit } from '@mui/icons-material';
3
3
  import { Box, IconButton, useTheme } from '@mui/material';
4
- import { useApp } from '@playcanvas/react/hooks';
5
- import { XRSPACE_LOCAL, XRTYPE_AR, XRTYPE_VR } from 'playcanvas';
6
4
  import useBoolean from '../../hooks/useBoolean';
7
5
  import { useCameraPosition } from '../../hooks/useCameraPosition';
6
+ import { useXr } from '../../hooks/useXr';
8
7
  import { getRgbaFromHex } from '../../utils/color';
9
8
  import useDeviceInfo from '../../utils/useDeviceInfo';
10
9
  import Button from '../Button/Button';
@@ -48,51 +47,19 @@ const SplatControls = ({
48
47
  const {
49
48
  isDesktop
50
49
  } = useDeviceInfo();
51
- const app = useApp();
52
50
  const {
53
51
  setCamera,
54
52
  getCameraState
55
53
  } = useCameraPosition();
56
- const [isArAvailable, setIsArAvailable] = useState(false);
57
- const [isVrAvailable, setIsVrAvailable] = useState(false);
54
+ const {
55
+ isXrAvailable,
56
+ startXr
57
+ } = useXr({
58
+ onError
59
+ });
58
60
  const [isInfoVisible, setIsInfoVisible] = useBoolean(true);
59
61
  const paneRef = useRef(null);
60
62
  const infoButtonRef = useRef(null);
61
- const errorCallback = useCallback(err => {
62
- if (err) {
63
- onError?.(err);
64
- app.xr?.end();
65
- }
66
- }, [app, onError]);
67
- const handleAr = useCallback(() => app.xr?.start(app.root.findComponent('camera'), XRTYPE_AR, XRSPACE_LOCAL, {
68
- callback: errorCallback
69
- }), [app, errorCallback]);
70
- const handleVr = useCallback(() => app.xr?.start(app.root.findComponent('camera'), XRTYPE_VR, XRSPACE_LOCAL, {
71
- callback: errorCallback
72
- }), [app, errorCallback]);
73
- useEffect(() => {
74
- // this can't be changed to `useMemo(() => app.xr?.isAvailable(XRTYPE_AR), [app])` because `app` doesn't update when
75
- // XR's availability is updated
76
- const handleAvailable = (type, available) => {
77
- if (type === XRTYPE_VR) {
78
- setIsVrAvailable(available);
79
- } else if (type === XRTYPE_AR) {
80
- setIsArAvailable(available);
81
- }
82
- };
83
-
84
- // Check current availability state on mount
85
- if (app.xr?.isAvailable(XRTYPE_VR)) {
86
- setIsVrAvailable(true);
87
- }
88
- if (app.xr?.isAvailable(XRTYPE_AR)) {
89
- setIsArAvailable(true);
90
- }
91
- app.xr?.on('available', handleAvailable);
92
- return () => {
93
- app.xr?.off('available', handleAvailable);
94
- };
95
- }, [app]);
96
63
  useEffect(() => {
97
64
  const handleKeyPress = event => {
98
65
  if (event.key === 'r' || event.key === 'R') {
@@ -171,12 +138,12 @@ const SplatControls = ({
171
138
  gap: 1,
172
139
  pointerEvents: 'auto'
173
140
  },
174
- children: [isArAvailable && !isEdit && /*#__PURE__*/_jsx(Button, {
141
+ children: [isXrAvailable('AR') && !isEdit && /*#__PURE__*/_jsx(Button, {
175
142
  label: strings.ar,
176
- onClick: handleAr
177
- }), isVrAvailable && !isEdit && /*#__PURE__*/_jsx(Button, {
143
+ onClick: () => startXr('AR')
144
+ }), isXrAvailable('VR') && !isEdit && /*#__PURE__*/_jsx(Button, {
178
145
  label: strings.vr,
179
- onClick: handleVr
146
+ onClick: () => startXr('VR')
180
147
  }), isDesktop && editable && !isEdit && onToggleEdit && /*#__PURE__*/_jsx(Button, {
181
148
  label: strings.edit,
182
149
  onClick: handleEdit
@@ -96,6 +96,13 @@ export declare class TfAnnotationManager extends PcAnnotationManager {
96
96
  * @private
97
97
  */
98
98
  _updateAnnotationPositions(annotation: any, resources: any, screenPos: any): void;
99
+ /**
100
+ * Override to also disable the hotspot mesh (not just the DOM) when the annotation is behind the
101
+ * camera. The base implementation leaves the mesh enabled, so a not-yet-scaled plane under a
102
+ * scaled content-root would stay huge in view until the camera moves the anchor in front.
103
+ * @private
104
+ */
105
+ _hideAnnotationElements(annotation: any, resources: any): void;
99
106
  /**
100
107
  * Override the scale update to clamp the world size to a maximum value.
101
108
  * Also scales the hotspot DOM element to match.
@@ -1 +1 @@
1
- {"version":3,"file":"TfAnnotationManager.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/TfAnnotationManager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoC,OAAO,EAAQ,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,iBAAiB,IAAI,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAIlG,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAelD;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,mBAAmB;IAC1D,MAAM,CAAC,UAAU,SAAyB;IAE1C,OAAO,CAAC,aAAa,CAAO;IAC5B,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,sBAAsB,CAAkB;IAChD,OAAO,CAAC,uBAAuB,CAAa;IAC5C,OAAO,CAAC,WAAW,CAAmD;IAEtE;;;;;;;;OAQG;IACH,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,EAE7B;IAED,IAAI,YAAY,IAJQ,MAAM,CAM7B;IAED;;;;;;;;;;OAUG;IACH,IAAI,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAEvC;IAED,IAAI,sBAAsB,IAJQ,MAAM,CAMvC;IAED;;OAEG;IACH,UAAU;IAgBV;;;;OAIG;IACH,eAAe;IAiBf;;;;OAIG;IACH,YAAY,CAAC,QAAQ,EAAE,kBAAkB;IAazC;;OAEG;IACH,MAAM;IAmCN;;;;OAIG;IACH,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAKnC;;;OAGG;IACH,oBAAoB,CAAC,UAAU,EAAE,GAAG;IAiBpC;;;;;OAKG;IACH,SAAS,CAAC,GAAG,EAAE,wBAAwB,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM;IAW/E;;;;OAIG;IACH,cAAc,CAAC,UAAU,EAAE,GAAG;IAI9B;;;;OAIG;IACH,sBAAsB,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG;IASlD,mBAAmB,CAAC,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO;IAKrD,0BAA0B;IAK1B,YAAY,CAAC,WAAW,EAAE,GAAG;IAK7B,aAAa,CAAC,WAAW,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM;IAI7C;;;OAGG;IACH,0BAA0B,CAAC,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG;IA6B1E;;;;OAIG;IACH,iCAAiC,CAAC,UAAU,EAAE,GAAG;IA2CjD;;;;OAIG;IACH,oBAAoB,CAAC,MAAM,EAAE,GAAG;IAUhC;;;OAGG;IACH,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,SAAuB,EAAE,WAAW,SAAI,EAAE,IAAI,CAAC,EAAE,kBAAkB;CAyD7G"}
1
+ {"version":3,"file":"TfAnnotationManager.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualWalkthrough/TfAnnotationManager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoC,OAAO,EAAQ,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,iBAAiB,IAAI,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAIlG,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAelD;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,mBAAmB;IAC1D,MAAM,CAAC,UAAU,SAAyB;IAE1C,OAAO,CAAC,aAAa,CAAO;IAC5B,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,sBAAsB,CAAkB;IAChD,OAAO,CAAC,uBAAuB,CAAa;IAC5C,OAAO,CAAC,WAAW,CAAmD;IAEtE;;;;;;;;OAQG;IACH,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,EAE7B;IAED,IAAI,YAAY,IAJQ,MAAM,CAM7B;IAED;;;;;;;;;;OAUG;IACH,IAAI,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAEvC;IAED,IAAI,sBAAsB,IAJQ,MAAM,CAMvC;IAED;;OAEG;IACH,UAAU;IAgBV;;;;OAIG;IACH,eAAe;IAiBf;;;;OAIG;IACH,YAAY,CAAC,QAAQ,EAAE,kBAAkB;IAazC;;OAEG;IACH,MAAM;IAmCN;;;;OAIG;IACH,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAcnC;;;OAGG;IACH,oBAAoB,CAAC,UAAU,EAAE,GAAG;IAiBpC;;;;;OAKG;IACH,SAAS,CAAC,GAAG,EAAE,wBAAwB,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM;IAW/E;;;;OAIG;IACH,cAAc,CAAC,UAAU,EAAE,GAAG;IAI9B;;;;OAIG;IACH,sBAAsB,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG;IASlD,mBAAmB,CAAC,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO;IAKrD,0BAA0B;IAK1B,YAAY,CAAC,WAAW,EAAE,GAAG;IAK7B,aAAa,CAAC,WAAW,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM;IAI7C;;;OAGG;IACH,0BAA0B,CAAC,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG;IA6B1E;;;;;OAKG;IACH,uBAAuB,CAAC,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG;IAMvD;;;;OAIG;IACH,iCAAiC,CAAC,UAAU,EAAE,GAAG;IAiDjD;;;;OAIG;IACH,oBAAoB,CAAC,MAAM,EAAE,GAAG;IAUhC;;;OAGG;IACH,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,SAAuB,EAAE,WAAW,SAAI,EAAE,IAAI,CAAC,EAAE,kBAAkB;CAyD7G"}
@@ -161,6 +161,15 @@ export class TfAnnotationManager extends PcAnnotationManager {
161
161
  _registerAnnotation(annotation) {
162
162
  super._registerAnnotation(annotation);
163
163
  this._applyAnnotationIcon(annotation);
164
+
165
+ // Keep the hotspot mesh hidden until the first scale pass clamps it. The annotation entity
166
+ // starts at unit local scale, so under a scaled content-root the plane would render many world
167
+ // units across for the frames before _updateAnnotationRotationAndScale runs.
168
+ const resources = this._annotationResources.get(annotation);
169
+ if (resources) {
170
+ resources.baseEntity.enabled = false;
171
+ resources.overlayEntity.enabled = false;
172
+ }
164
173
  }
165
174
 
166
175
  /**
@@ -269,6 +278,18 @@ export class TfAnnotationManager extends PcAnnotationManager {
269
278
  }
270
279
  }
271
280
 
281
+ /**
282
+ * Override to also disable the hotspot mesh (not just the DOM) when the annotation is behind the
283
+ * camera. The base implementation leaves the mesh enabled, so a not-yet-scaled plane under a
284
+ * scaled content-root would stay huge in view until the camera moves the anchor in front.
285
+ * @private
286
+ */
287
+ _hideAnnotationElements(annotation, resources) {
288
+ super._hideAnnotationElements(annotation, resources);
289
+ resources.baseEntity.enabled = false;
290
+ resources.overlayEntity.enabled = false;
291
+ }
292
+
272
293
  /**
273
294
  * Override the scale update to clamp the world size to a maximum value.
274
295
  * Also scales the hotspot DOM element to match.
@@ -305,6 +326,12 @@ export class TfAnnotationManager extends PcAnnotationManager {
305
326
  // size, so it uses the true _hotspotSize and the clamp ratio only (never the
306
327
  // parent scale, which the DOM overlay does not inherit).
307
328
  const resources = this._annotationResources.get(annotation);
329
+ if (resources) {
330
+ // This branch only runs for annotations in front of the camera, and the scale above is now
331
+ // clamped, so it is safe to reveal the mesh (hidden on register / when behind the camera).
332
+ resources.baseEntity.enabled = true;
333
+ resources.overlayEntity.enabled = true;
334
+ }
308
335
  if (resources && resources.hotspotDom) {
309
336
  const clampRatio = clampedScale / unclampedScale;
310
337
  const baseSize = this._hotspotSize + 5; // Match the +5 from the stylesheet
@@ -0,0 +1,12 @@
1
+ export type XrType = 'VR' | 'AR';
2
+ interface UseXrOptions {
3
+ onError?: (error: Error) => void;
4
+ }
5
+ export declare const useXr: ({ onError }?: UseXrOptions) => {
6
+ isXrAvailable: (type: XrType) => boolean;
7
+ startXr: (type: XrType) => void;
8
+ endXr: () => void;
9
+ isCurrentlyInXr: boolean;
10
+ };
11
+ export default useXr;
12
+ //# sourceMappingURL=useXr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useXr.d.ts","sourceRoot":"","sources":["../../src/hooks/useXr.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;AAEjC,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAOD,eAAO,MAAM,KAAK,GAAI,cAAa,YAAiB;0BA0CT,MAAM;oBAGtC,MAAM;;;CAsBhB,CAAC;AAEF,eAAe,KAAK,CAAC"}
package/hooks/useXr.js ADDED
@@ -0,0 +1,74 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { useApp } from '@playcanvas/react/hooks';
3
+ import { XRSPACE_LOCALFLOOR, XRTYPE_AR, XRTYPE_VR } from 'playcanvas';
4
+ const XR_TYPES = {
5
+ VR: XRTYPE_VR,
6
+ AR: XRTYPE_AR
7
+ };
8
+ export const useXr = ({
9
+ onError
10
+ } = {}) => {
11
+ const app = useApp();
12
+ const [available, setAvailable] = useState({
13
+ VR: false,
14
+ AR: false
15
+ });
16
+ const [isCurrentlyInXr, setIsCurrentlyInXr] = useState(app.xr?.active ?? false);
17
+ useEffect(() => {
18
+ // We subscribe to the manager directly because `app` doesn't update when XR's availability changes.
19
+ const handleAvailable = (type, isAvailable) => {
20
+ if (type === XRTYPE_VR) {
21
+ setAvailable(prev => ({
22
+ ...prev,
23
+ VR: isAvailable
24
+ }));
25
+ } else if (type === XRTYPE_AR) {
26
+ setAvailable(prev => ({
27
+ ...prev,
28
+ AR: isAvailable
29
+ }));
30
+ }
31
+ };
32
+ setAvailable({
33
+ VR: app.xr?.isAvailable(XRTYPE_VR) ?? false,
34
+ AR: app.xr?.isAvailable(XRTYPE_AR) ?? false
35
+ });
36
+ app.xr?.on('available', handleAvailable);
37
+ return () => {
38
+ app.xr?.off('available', handleAvailable);
39
+ };
40
+ }, [app]);
41
+ useEffect(() => {
42
+ const handleStart = () => setIsCurrentlyInXr(true);
43
+ const handleEnd = () => setIsCurrentlyInXr(false);
44
+ setIsCurrentlyInXr(app.xr?.active ?? false);
45
+ app.xr?.on('start', handleStart);
46
+ app.xr?.on('end', handleEnd);
47
+ return () => {
48
+ app.xr?.off('start', handleStart);
49
+ app.xr?.off('end', handleEnd);
50
+ };
51
+ }, [app]);
52
+ const isXrAvailable = useCallback(type => available[type], [available]);
53
+ const startXr = useCallback(type => {
54
+ const camera = app.root.findComponent('camera');
55
+ app.xr?.start(camera, XR_TYPES[type], XRSPACE_LOCALFLOOR, {
56
+ callback: err => {
57
+ if (err) {
58
+ onError?.(err);
59
+ app.xr?.end();
60
+ }
61
+ }
62
+ });
63
+ }, [app, onError]);
64
+ const endXr = useCallback(() => {
65
+ app.xr?.end();
66
+ }, [app]);
67
+ return useMemo(() => ({
68
+ isXrAvailable,
69
+ startXr,
70
+ endXr,
71
+ isCurrentlyInXr
72
+ }), [isXrAvailable, startXr, endXr, isCurrentlyInXr]);
73
+ };
74
+ export default useXr;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@terraware/web-components",
3
- "version": "4.2.19",
3
+ "version": "4.2.20",
4
4
  "author": "Terraformation Inc.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {