@webspatial/react-sdk 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/web/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  (function(){
3
3
  if(typeof window === 'undefined') return;
4
4
  if(!window.__webspatialsdk__) window.__webspatialsdk__ = {}
5
- window.__webspatialsdk__['react-sdk-version'] = "1.5.0"
5
+ window.__webspatialsdk__['react-sdk-version'] = "1.6.0"
6
6
  window.__webspatialsdk__['XR_ENV'] = "web"
7
7
  })()
8
8
 
@@ -145,11 +145,20 @@ function joinToCSSText(cssKV) {
145
145
  }
146
146
 
147
147
  // src/spatialized-container/hooks/useDomProxy.ts
148
- function makeOriginalKey(key) {
149
- return `__original_${key}`;
150
- }
151
148
  var SpatialContainerRefProxy = class {
152
149
  transformVisibilityTaskContainerDom = null;
150
+ /** Raw Standard host element (styled root). Used to mirror class onto the transform probe. */
151
+ standardRawDom = null;
152
+ standardClassObserver = null;
153
+ /**
154
+ * When set, Standard's DOM className is forwarded here so TransformVisibilityTaskContainer
155
+ * can render it from React state (avoids React clobbering imperative class updates).
156
+ */
157
+ mirrorClassNotify = null;
158
+ /** Last class string applied to the probe + used to skip redundant syncs. */
159
+ lastMirroredClassName = null;
160
+ /** Coalesce multiple class sync triggers in the same turn (Observer + classList, etc.). */
161
+ classSyncMicrotaskQueued = false;
153
162
  ref;
154
163
  domProxy;
155
164
  styleProxy;
@@ -159,211 +168,263 @@ var SpatialContainerRefProxy = class {
159
168
  this.ref = ref;
160
169
  this.extraRefProps = extraRefProps;
161
170
  }
171
+ setMirrorClassNotify(fn) {
172
+ this.mirrorClassNotify = fn;
173
+ if (fn && this.standardRawDom) {
174
+ this.flushSyncTransformClassFromStandard(true);
175
+ }
176
+ }
177
+ disconnectStandardClassObserver() {
178
+ this.standardClassObserver?.disconnect();
179
+ this.standardClassObserver = null;
180
+ }
181
+ attachStandardClassObserver() {
182
+ this.disconnectStandardClassObserver();
183
+ if (!this.standardRawDom) {
184
+ return;
185
+ }
186
+ this.standardClassObserver = new MutationObserver(() => {
187
+ this.scheduleSyncTransformClassFromStandard();
188
+ });
189
+ this.standardClassObserver.observe(this.standardRawDom, {
190
+ attributes: true,
191
+ attributeFilter: ["class"]
192
+ });
193
+ }
194
+ /**
195
+ * Merge multiple sync requests (e.g. classList hook + MutationObserver) into one microtask.
196
+ */
197
+ scheduleSyncTransformClassFromStandard() {
198
+ if (this.classSyncMicrotaskQueued) {
199
+ return;
200
+ }
201
+ this.classSyncMicrotaskQueued = true;
202
+ queueMicrotask(() => {
203
+ this.classSyncMicrotaskQueued = false;
204
+ this.flushSyncTransformClassFromStandard(false);
205
+ });
206
+ }
207
+ /**
208
+ * Source of truth: Standard host DOM (incl. styled-components runtime class changes).
209
+ * @param force when true, skip same-string short-circuit (e.g. mirror notify just registered).
210
+ */
211
+ flushSyncTransformClassFromStandard(force) {
212
+ if (!this.standardRawDom) {
213
+ return;
214
+ }
215
+ const name = this.standardRawDom.className;
216
+ const probe = this.transformVisibilityTaskContainerDom;
217
+ if (!force && probe && probe.className === name && this.lastMirroredClassName === name) {
218
+ return;
219
+ }
220
+ this.lastMirroredClassName = name;
221
+ if (probe) {
222
+ probe.className = name;
223
+ }
224
+ this.mirrorClassNotify?.(name);
225
+ }
162
226
  updateStandardSpatializedContainerDom(dom) {
163
227
  const self = this;
164
- if (dom) {
165
- let cacheExtraRefProps;
166
- const domProxy = new Proxy(
167
- dom,
168
- {
169
- get(target, prop) {
170
- if (prop === "__raw") {
171
- return target;
172
- }
173
- if (prop === "xrClientDepth") {
174
- return target.style.getPropertyValue(SpatialCustomStyleVars.depth);
175
- }
176
- if (prop === "xrOffsetBack") {
177
- return target.style.getPropertyValue(SpatialCustomStyleVars.back);
178
- }
179
- if (prop === "style") {
180
- if (!self.styleProxy) {
181
- self.styleProxy = new Proxy(target.style, {
182
- get(target2, prop2) {
183
- if (prop2 === "visibility" || prop2 === "transform") {
184
- return self.transformVisibilityTaskContainerDom?.style.getPropertyValue(
185
- prop2
186
- );
187
- }
188
- const value2 = Reflect.get(target2, prop2);
189
- if (typeof value2 === "function") {
190
- if (prop2 === "setProperty" || prop2 === "removeProperty" || prop2 === "getPropertyValue") {
191
- return function(...args) {
192
- const validProperties = ["visibility", "transform"];
193
- const [property] = args;
194
- if (validProperties.includes(property)) {
195
- if (prop2 === "setProperty") {
196
- const [, kValue] = args;
197
- self.transformVisibilityTaskContainerDom?.style.setProperty(
198
- property,
199
- kValue
200
- );
201
- } else if (prop2 === "removeProperty") {
202
- self.transformVisibilityTaskContainerDom?.style.removeProperty(
203
- property
204
- );
205
- } else if (prop2 === "getPropertyValue") {
206
- return self.transformVisibilityTaskContainerDom?.style.getPropertyValue(
207
- property
208
- );
209
- }
210
- } else {
211
- return value2.apply(this, args);
228
+ if (!dom) {
229
+ this.disconnectStandardClassObserver();
230
+ this.standardRawDom = null;
231
+ this.lastMirroredClassName = null;
232
+ this.domProxy = void 0;
233
+ this.styleProxy = void 0;
234
+ this.updateDomProxyToRef();
235
+ return;
236
+ }
237
+ this.standardRawDom = dom;
238
+ let cacheExtraRefProps;
239
+ const domProxy = new Proxy(
240
+ dom,
241
+ {
242
+ get(target, prop) {
243
+ if (prop === "__raw") {
244
+ return target;
245
+ }
246
+ if (prop === "xrClientDepth") {
247
+ return target.style.getPropertyValue(SpatialCustomStyleVars.depth);
248
+ }
249
+ if (prop === "xrOffsetBack") {
250
+ return target.style.getPropertyValue(SpatialCustomStyleVars.back);
251
+ }
252
+ if (prop === "style") {
253
+ if (!self.styleProxy) {
254
+ self.styleProxy = new Proxy(target.style, {
255
+ get(target2, prop2) {
256
+ if (prop2 === "visibility" || prop2 === "transform") {
257
+ return self.transformVisibilityTaskContainerDom?.style.getPropertyValue(
258
+ prop2
259
+ );
260
+ }
261
+ const value2 = Reflect.get(target2, prop2);
262
+ if (typeof value2 === "function") {
263
+ if (prop2 === "setProperty" || prop2 === "removeProperty" || prop2 === "getPropertyValue") {
264
+ return function(...args) {
265
+ const validProperties = ["visibility", "transform"];
266
+ const [property] = args;
267
+ if (validProperties.includes(property)) {
268
+ if (prop2 === "setProperty") {
269
+ const [, kValue] = args;
270
+ self.transformVisibilityTaskContainerDom?.style.setProperty(
271
+ property,
272
+ kValue
273
+ );
274
+ } else if (prop2 === "removeProperty") {
275
+ self.transformVisibilityTaskContainerDom?.style.removeProperty(
276
+ property
277
+ );
278
+ } else if (prop2 === "getPropertyValue") {
279
+ return self.transformVisibilityTaskContainerDom?.style.getPropertyValue(
280
+ property
281
+ );
212
282
  }
213
- }.bind(target2);
214
- } else {
215
- return value2.bind(target2);
216
- }
217
- } else {
218
- return value2;
219
- }
220
- },
221
- set(target2, prop2, value2) {
222
- if (prop2 === "visibility") {
223
- self.transformVisibilityTaskContainerDom?.style.setProperty(
224
- "visibility",
225
- value2
226
- );
227
- return true;
228
- }
229
- if (prop2 === "transform") {
230
- self.transformVisibilityTaskContainerDom?.style.setProperty(
231
- "transform",
232
- value2
233
- );
234
- return true;
235
- }
236
- if (prop2 === SpatialCustomStyleVars.backgroundMaterial) {
237
- target2.setProperty(
238
- SpatialCustomStyleVars.backgroundMaterial,
239
- value2
240
- );
241
- } else if (prop2 === SpatialCustomStyleVars.back) {
242
- target2.setProperty(
243
- SpatialCustomStyleVars.back,
244
- value2
245
- );
246
- } else if (prop2 === SpatialCustomStyleVars.xrZIndex) {
247
- target2.setProperty(
248
- SpatialCustomStyleVars.xrZIndex,
249
- value2
250
- );
251
- } else if (prop2 === SpatialCustomStyleVars.depth) {
252
- target2.setProperty(
253
- SpatialCustomStyleVars.depth,
254
- value2
255
- );
256
- } else if (prop2 === "cssText") {
257
- const toFilteredCSSProperties = [
258
- "transform",
259
- "visibility"
260
- ];
261
- const { extractedValues, filteredCssText } = extractAndRemoveCustomProperties(
262
- value2,
263
- toFilteredCSSProperties
264
- );
265
- toFilteredCSSProperties.forEach((key) => {
266
- if (extractedValues[key]) {
267
- self.transformVisibilityTaskContainerDom?.style.setProperty(
268
- key,
269
- extractedValues[key]
270
- );
271
283
  } else {
272
- target2.removeProperty(key);
284
+ return value2.apply(this, args);
273
285
  }
274
- });
275
- const appendedCSSText = joinToCSSText({
276
- transform: "none",
277
- visibility: "hidden"
278
- });
279
- return Reflect.set(
280
- target2,
281
- prop2,
282
- [appendedCSSText, filteredCssText].join(";")
283
- );
286
+ }.bind(target2);
287
+ } else {
288
+ return value2.bind(target2);
284
289
  }
285
- return Reflect.set(target2, prop2, value2);
290
+ } else {
291
+ return value2;
286
292
  }
287
- });
288
- }
289
- return self.styleProxy;
290
- }
291
- if (typeof prop === "string" && self.extraRefProps) {
292
- if (!cacheExtraRefProps) {
293
- cacheExtraRefProps = self.extraRefProps(domProxy);
294
- }
295
- const extraProps = cacheExtraRefProps;
296
- if (extraProps.hasOwnProperty(prop)) {
297
- return extraProps[prop];
298
- }
299
- }
300
- const value = Reflect.get(target, prop);
301
- if (typeof value === "function") {
302
- if ("removeAttribute" === prop) {
303
- return function(...args) {
304
- const [property] = args;
305
- if (property === "style") {
306
- dom.style.cssText = "visibility: hidden; transition: none; transform: none;";
307
- if (self.transformVisibilityTaskContainerDom) {
308
- self.transformVisibilityTaskContainerDom.style.visibility = "";
309
- self.transformVisibilityTaskContainerDom.style.transform = "";
310
- }
293
+ },
294
+ set(target2, prop2, value2) {
295
+ if (prop2 === "visibility") {
296
+ self.transformVisibilityTaskContainerDom?.style.setProperty(
297
+ "visibility",
298
+ value2
299
+ );
311
300
  return true;
312
301
  }
313
- if (property === "class") {
314
- domProxy.className = "xr-spatial-default";
302
+ if (prop2 === "transform") {
303
+ self.transformVisibilityTaskContainerDom?.style.setProperty(
304
+ "transform",
305
+ value2
306
+ );
315
307
  return true;
316
308
  }
317
- };
318
- }
319
- return value.bind(target);
309
+ if (prop2 === SpatialCustomStyleVars.backgroundMaterial) {
310
+ target2.setProperty(
311
+ SpatialCustomStyleVars.backgroundMaterial,
312
+ value2
313
+ );
314
+ } else if (prop2 === SpatialCustomStyleVars.back) {
315
+ target2.setProperty(
316
+ SpatialCustomStyleVars.back,
317
+ value2
318
+ );
319
+ } else if (prop2 === SpatialCustomStyleVars.xrZIndex) {
320
+ target2.setProperty(
321
+ SpatialCustomStyleVars.xrZIndex,
322
+ value2
323
+ );
324
+ } else if (prop2 === SpatialCustomStyleVars.depth) {
325
+ target2.setProperty(
326
+ SpatialCustomStyleVars.depth,
327
+ value2
328
+ );
329
+ } else if (prop2 === "cssText") {
330
+ const toFilteredCSSProperties = ["transform", "visibility"];
331
+ const { extractedValues, filteredCssText } = extractAndRemoveCustomProperties(
332
+ value2,
333
+ toFilteredCSSProperties
334
+ );
335
+ toFilteredCSSProperties.forEach((key) => {
336
+ if (extractedValues[key]) {
337
+ self.transformVisibilityTaskContainerDom?.style.setProperty(
338
+ key,
339
+ extractedValues[key]
340
+ );
341
+ } else {
342
+ target2.removeProperty(key);
343
+ }
344
+ });
345
+ const appendedCSSText = joinToCSSText({
346
+ transform: "none",
347
+ visibility: "hidden"
348
+ });
349
+ return Reflect.set(
350
+ target2,
351
+ prop2,
352
+ [appendedCSSText, filteredCssText].join(";")
353
+ );
354
+ }
355
+ return Reflect.set(target2, prop2, value2);
356
+ }
357
+ });
320
358
  }
321
- return value;
322
- },
323
- set(target, prop, value) {
324
- if (prop === "className") {
325
- if (value && value.indexOf("xr-spatial-default") === -1) {
326
- value = value + " xr-spatial-default";
327
- }
328
- if (self.transformVisibilityTaskContainerDom) {
329
- self.transformVisibilityTaskContainerDom.className = value;
330
- }
359
+ return self.styleProxy;
360
+ }
361
+ if (typeof prop === "string" && self.extraRefProps) {
362
+ if (!cacheExtraRefProps) {
363
+ cacheExtraRefProps = self.extraRefProps(domProxy);
331
364
  }
332
- if (typeof prop === "string" && self.extraRefProps) {
333
- if (!cacheExtraRefProps) {
334
- cacheExtraRefProps = self.extraRefProps(domProxy);
335
- }
336
- cacheExtraRefProps[prop] = value;
365
+ const extraProps = cacheExtraRefProps;
366
+ if (extraProps.hasOwnProperty(prop)) {
367
+ return extraProps[prop];
337
368
  }
338
- return Reflect.set(target, prop, value);
339
369
  }
340
- }
341
- );
342
- this.domProxy = domProxy;
343
- const domClassList = dom.classList;
344
- const domClassMethodKeys = ["add", "remove", "toggle", "replace"];
345
- domClassMethodKeys.forEach((key) => {
346
- const hiddenKey = makeOriginalKey(key);
347
- const hiddenKeyExist = domClassList[hiddenKey] !== void 0;
348
- const originalMethod = hiddenKeyExist ? domClassList[hiddenKey] : domClassList[key].bind(domClassList);
349
- domClassList[hiddenKey] = originalMethod;
350
- domClassList[key] = function(...args) {
351
- const result = originalMethod(...args);
352
- if (self.transformVisibilityTaskContainerDom) {
353
- self.transformVisibilityTaskContainerDom.className = dom.className;
370
+ const value = Reflect.get(target, prop);
371
+ if (typeof value === "function") {
372
+ if ("removeAttribute" === prop) {
373
+ return function(...args) {
374
+ const [property] = args;
375
+ if (property === "style") {
376
+ dom.style.cssText = "visibility: hidden; transition: none; transform: none;";
377
+ if (self.transformVisibilityTaskContainerDom) {
378
+ self.transformVisibilityTaskContainerDom.style.visibility = "";
379
+ self.transformVisibilityTaskContainerDom.style.transform = "";
380
+ }
381
+ return true;
382
+ }
383
+ if (property === "class") {
384
+ domProxy.className = "xr-spatial-default";
385
+ return true;
386
+ }
387
+ };
388
+ }
389
+ return value.bind(target);
354
390
  }
355
- return result;
356
- };
357
- });
358
- this.styleProxy = void 0;
359
- this.updateDomProxyToRef();
360
- Object.assign(dom, {
361
- __targetProxy: domProxy
362
- });
363
- }
391
+ return value;
392
+ },
393
+ set(target, prop, value) {
394
+ if (prop === "className") {
395
+ if (value && String(value).indexOf("xr-spatial-default") === -1) {
396
+ value = value + " xr-spatial-default";
397
+ }
398
+ }
399
+ if (typeof prop === "string" && self.extraRefProps) {
400
+ if (!cacheExtraRefProps) {
401
+ cacheExtraRefProps = self.extraRefProps(domProxy);
402
+ }
403
+ cacheExtraRefProps[prop] = value;
404
+ }
405
+ const ok = Reflect.set(target, prop, value);
406
+ if (ok && prop === "className") {
407
+ self.scheduleSyncTransformClassFromStandard();
408
+ }
409
+ return ok;
410
+ }
411
+ }
412
+ );
413
+ this.domProxy = domProxy;
414
+ this.styleProxy = void 0;
415
+ this.updateDomProxyToRef();
416
+ Object.assign(dom, {
417
+ __targetProxy: domProxy
418
+ });
419
+ this.attachStandardClassObserver();
420
+ this.scheduleSyncTransformClassFromStandard();
364
421
  }
365
422
  updateTransformVisibilityTaskContainerDom(dom) {
366
423
  this.transformVisibilityTaskContainerDom = dom;
424
+ if (!dom) {
425
+ this.lastMirroredClassName = null;
426
+ }
427
+ this.scheduleSyncTransformClassFromStandard();
367
428
  this.updateDomProxyToRef();
368
429
  }
369
430
  updateDomProxyToRef() {
@@ -843,13 +904,20 @@ var TransformVisibilityTaskContainer = forwardRef2(
843
904
  );
844
905
 
845
906
  // src/spatialized-container/SpatializedContainer.tsx
846
- import { forwardRef as forwardRef4, useContext as useContext7, useEffect as useEffect10, useMemo as useMemo2 } from "react";
907
+ import {
908
+ forwardRef as forwardRef4,
909
+ useCallback as useCallback6,
910
+ useContext as useContext7,
911
+ useEffect as useEffect10,
912
+ useMemo as useMemo2,
913
+ useState as useState6
914
+ } from "react";
847
915
 
848
916
  // src/noRuntime.ts
849
917
  var Spatial = class {
850
918
  /**
851
919
  * Requests a session object from the browser
852
- * @returns The session or null if not availible in the current browser
920
+ * @returns The session or null if not available in the current browser
853
921
  * [TODO] discuss implications of this not being async
854
922
  */
855
923
  requestSession() {
@@ -871,14 +939,14 @@ var Spatial = class {
871
939
  }
872
940
  /**
873
941
  * Gets the native version, format is "x.x.x"
874
- * @returns native version string
942
+ * @returns native version string, or null when runtime is unavailable
875
943
  */
876
944
  getNativeVersion() {
877
945
  return null;
878
946
  }
879
947
  /**
880
948
  * Gets the client version, format is "x.x.x"
881
- * @returns client version string
949
+ * @returns client version string, or null when runtime is unavailable
882
950
  */
883
951
  getClientVersion() {
884
952
  return null;
@@ -898,7 +966,7 @@ var PhysicalMetrics = {
898
966
  meterToPtUnscaled: 1360,
899
967
  meterToPtScaled: 1360
900
968
  }),
901
- subscribe: (cb) => {
969
+ subscribe: (cb) => () => {
902
970
  }
903
971
  };
904
972
 
@@ -1203,7 +1271,7 @@ function renderPlaceholderInSubPortal(portalInstanceObject, El) {
1203
1271
  return /* @__PURE__ */ jsx3(Fragment, {});
1204
1272
  }
1205
1273
  const { width, height } = portalInstanceObject.domRect;
1206
- const display = portalInstanceObject.computedStyle.getPropertyPriority("display");
1274
+ const display = portalInstanceObject.computedStyle.getPropertyValue("display");
1207
1275
  const spatialIdProps = { [SpatialID]: spatialId };
1208
1276
  return /* @__PURE__ */ jsx3(
1209
1277
  El,
@@ -1648,6 +1716,20 @@ function SpatializedContainerBase(inprops, ref) {
1648
1716
  standardSpatializedContainerCallback,
1649
1717
  spatialContainerRefProxy
1650
1718
  } = useDomProxy(ref, extraRefProps);
1719
+ const [probeClassName, setProbeClassName] = useState6(
1720
+ () => props.className ?? ""
1721
+ );
1722
+ const notifyProbeClass = useCallback6((name) => {
1723
+ setProbeClassName((prev) => prev === name ? prev : name);
1724
+ }, []);
1725
+ useEffect10(() => {
1726
+ spatialContainerRefProxy.current.setMirrorClassNotify?.(
1727
+ notifyProbeClass
1728
+ );
1729
+ return () => {
1730
+ spatialContainerRefProxy.current.setMirrorClassNotify?.(null);
1731
+ };
1732
+ }, [spatialContainerRefProxy, notifyProbeClass]);
1651
1733
  useEffect10(() => {
1652
1734
  rootSpatializedContainerObject.updateSpatialContainerRefProxyInfo(
1653
1735
  spatialId,
@@ -1676,7 +1758,7 @@ function SpatializedContainerBase(inprops, ref) {
1676
1758
  {
1677
1759
  ref: transformVisibilityTaskContainerCallback,
1678
1760
  ...spatialIdProps,
1679
- className: props.className,
1761
+ className: probeClassName,
1680
1762
  style: props.style
1681
1763
  }
1682
1764
  )
@@ -1688,6 +1770,18 @@ function SpatializedContainerBase(inprops, ref) {
1688
1770
  standardSpatializedContainerCallback,
1689
1771
  spatialContainerRefProxy
1690
1772
  } = useDomProxy(ref, extraRefProps);
1773
+ const [probeClassName, setProbeClassName] = useState6(
1774
+ () => props.className ?? ""
1775
+ );
1776
+ const notifyProbeClass = useCallback6((name) => {
1777
+ setProbeClassName((prev) => prev === name ? prev : name);
1778
+ }, []);
1779
+ useEffect10(() => {
1780
+ spatialContainerRefProxy.current.setMirrorClassNotify?.(notifyProbeClass);
1781
+ return () => {
1782
+ spatialContainerRefProxy.current.setMirrorClassNotify?.(null);
1783
+ };
1784
+ }, [spatialContainerRefProxy, notifyProbeClass]);
1691
1785
  const spatialEvents = useSpatialEvents(
1692
1786
  {
1693
1787
  onSpatialTap,
@@ -1739,7 +1833,7 @@ function SpatializedContainerBase(inprops, ref) {
1739
1833
  {
1740
1834
  ref: transformVisibilityTaskContainerCallback,
1741
1835
  ...spatialIdProps,
1742
- className: props.className,
1836
+ className: probeClassName,
1743
1837
  style: props.style
1744
1838
  }
1745
1839
  )
@@ -2019,8 +2113,10 @@ var Spatialized2DElementContainer = forwardRef5(
2019
2113
 
2020
2114
  // src/spatialized-container/SpatializedStatic3DElementContainer.tsx
2021
2115
  import {
2116
+ Children,
2022
2117
  forwardRef as forwardRef6,
2023
- useCallback as useCallback6,
2118
+ isValidElement,
2119
+ useCallback as useCallback7,
2024
2120
  useContext as useContext9,
2025
2121
  useEffect as useEffect13,
2026
2122
  useMemo as useMemo3,
@@ -2028,9 +2124,7 @@ import {
2028
2124
  } from "react";
2029
2125
  import { Fragment as Fragment2, jsx as jsx8 } from "react/jsx-runtime";
2030
2126
  function getAbsoluteURL(url) {
2031
- if (!url) {
2032
- return "";
2033
- }
2127
+ if (!url) return url;
2034
2128
  try {
2035
2129
  return new URL(url, document.baseURI).toString();
2036
2130
  } catch {
@@ -2058,21 +2152,34 @@ function createLoadFailureEvent(targetGetter) {
2058
2152
  function createLoadSuccessEvent(targetGetter) {
2059
2153
  return createLoadEvent("modelloaded", targetGetter);
2060
2154
  }
2155
+ function collectSources(children) {
2156
+ const sources = [];
2157
+ Children.forEach(children, (child) => {
2158
+ if (isValidElement(child) && child.type === "source") {
2159
+ const { src, type } = child.props;
2160
+ if (src) {
2161
+ sources.push({ src: getAbsoluteURL(src), type });
2162
+ }
2163
+ }
2164
+ });
2165
+ return sources;
2166
+ }
2061
2167
  function SpatializedContent2(props) {
2062
- const { src, spatializedElement, onLoad, onError } = props;
2063
- const spatializedStatic3DElement = spatializedElement;
2064
- const portalInstanceObject = useContext9(
2065
- PortalInstanceContext
2066
- );
2067
- const currentSrc = useMemo3(() => getAbsoluteURL(src), [src]);
2168
+ const { src, children, spatializedElement, onLoad, onError, autoPlay, loop } = props;
2169
+ const portalInstanceObject = useContext9(PortalInstanceContext);
2170
+ const modelURL = useMemo3(() => getAbsoluteURL(src), [src]);
2171
+ const sources = useMemo3(() => collectSources(children), [children]);
2068
2172
  useEffect13(() => {
2069
- if (src) {
2070
- spatializedStatic3DElement.updateProperties({ modelURL: currentSrc });
2071
- }
2072
- }, [currentSrc]);
2173
+ spatializedElement.updateProperties({
2174
+ modelURL: modelURL ?? "",
2175
+ sources,
2176
+ autoplay: autoPlay,
2177
+ loop
2178
+ });
2179
+ }, [modelURL, JSON.stringify(sources), autoPlay, loop]);
2073
2180
  useEffect13(() => {
2074
2181
  if (onLoad) {
2075
- spatializedStatic3DElement.onLoadCallback = () => {
2182
+ spatializedElement.onLoadCallback = () => {
2076
2183
  onLoad(
2077
2184
  createLoadSuccessEvent(
2078
2185
  () => portalInstanceObject.dom.__targetProxy
@@ -2080,12 +2187,12 @@ function SpatializedContent2(props) {
2080
2187
  );
2081
2188
  };
2082
2189
  } else {
2083
- spatializedStatic3DElement.onLoadCallback = void 0;
2190
+ spatializedElement.onLoadCallback = void 0;
2084
2191
  }
2085
2192
  }, [onLoad]);
2086
2193
  useEffect13(() => {
2087
2194
  if (onError) {
2088
- spatializedStatic3DElement.onLoadFailureCallback = () => {
2195
+ spatializedElement.onLoadFailureCallback = () => {
2089
2196
  onError(
2090
2197
  createLoadFailureEvent(
2091
2198
  () => portalInstanceObject.dom.__targetProxy
@@ -2093,24 +2200,27 @@ function SpatializedContent2(props) {
2093
2200
  );
2094
2201
  };
2095
2202
  } else {
2096
- spatializedStatic3DElement.onLoadFailureCallback = void 0;
2203
+ spatializedElement.onLoadFailureCallback = void 0;
2097
2204
  }
2098
2205
  }, [onError]);
2099
2206
  return /* @__PURE__ */ jsx8(Fragment2, {});
2100
2207
  }
2101
2208
  function SpatializedStatic3DElementContainerBase(props, ref) {
2102
2209
  const promiseRef = useRef5(null);
2103
- const createSpatializedElement2 = useCallback6(() => {
2104
- const url = getAbsoluteURL(props.src);
2105
- promiseRef.current = getSession().createSpatializedStatic3DElement(url);
2210
+ const createSpatializedElement2 = useCallback7(() => {
2211
+ promiseRef.current = getSession().createSpatializedStatic3DElement(
2212
+ getAbsoluteURL(props.src),
2213
+ collectSources(props.children)
2214
+ );
2106
2215
  return promiseRef.current;
2107
2216
  }, []);
2108
- const extraRefProps = useCallback6(
2217
+ const extraRefProps = useCallback7(
2109
2218
  (domProxy) => {
2110
2219
  let modelTransform = new DOMMatrixReadOnly();
2111
2220
  return {
2112
2221
  get currentSrc() {
2113
- return getAbsoluteURL(props.src);
2222
+ const spatializedElement = domProxy.__spatializedElement;
2223
+ return spatializedElement?.currentSrc ?? "";
2114
2224
  },
2115
2225
  get ready() {
2116
2226
  return promiseRef.current.then((spatializedElement) => spatializedElement.ready).then((success) => {
@@ -2125,6 +2235,32 @@ function SpatializedStatic3DElementContainerBase(props, ref) {
2125
2235
  modelTransform = value;
2126
2236
  const spatializedElement = domProxy.__spatializedElement;
2127
2237
  spatializedElement?.updateModelTransform(modelTransform);
2238
+ },
2239
+ async play() {
2240
+ const spatializedElement = domProxy.__spatializedElement;
2241
+ await spatializedElement?.play();
2242
+ },
2243
+ async pause() {
2244
+ const spatializedElement = domProxy.__spatializedElement;
2245
+ await spatializedElement?.pause();
2246
+ },
2247
+ get paused() {
2248
+ const spatializedElement = domProxy.__spatializedElement;
2249
+ return spatializedElement?.paused ?? true;
2250
+ },
2251
+ get duration() {
2252
+ const spatializedElement = domProxy.__spatializedElement;
2253
+ return spatializedElement?.duration ?? 0;
2254
+ },
2255
+ get playbackRate() {
2256
+ const spatializedElement = domProxy.__spatializedElement;
2257
+ return spatializedElement?.playbackRate ?? 1;
2258
+ },
2259
+ set playbackRate(value) {
2260
+ const spatializedElement = domProxy.__spatializedElement;
2261
+ if (spatializedElement) {
2262
+ spatializedElement.playbackRate = value;
2263
+ }
2128
2264
  }
2129
2265
  };
2130
2266
  },
@@ -2937,10 +3073,10 @@ var useEntity = ({
2937
3073
  };
2938
3074
 
2939
3075
  // src/reality/hooks/useForceUpdate.tsx
2940
- import { useCallback as useCallback7, useState as useState6 } from "react";
3076
+ import { useCallback as useCallback8, useState as useState7 } from "react";
2941
3077
  var useForceUpdate2 = () => {
2942
- const [, setTick] = useState6(0);
2943
- return useCallback7(() => setTick((tick) => tick + 1), []);
3078
+ const [, setTick] = useState7(0);
3079
+ return useCallback8(() => setTick((tick) => tick + 1), []);
2944
3080
  };
2945
3081
 
2946
3082
  // src/reality/components/BaseEntity.tsx
@@ -3363,10 +3499,10 @@ var ModelEntity = forwardRef18(
3363
3499
  // src/reality/components/Reality.tsx
3364
3500
  import {
3365
3501
  forwardRef as forwardRef19,
3366
- useCallback as useCallback8,
3502
+ useCallback as useCallback9,
3367
3503
  useEffect as useEffect26,
3368
3504
  useRef as useRef16,
3369
- useState as useState7
3505
+ useState as useState8
3370
3506
  } from "react";
3371
3507
  import { Fragment as Fragment3, jsx as jsx22, jsxs as jsxs3 } from "react/jsx-runtime";
3372
3508
  var Reality = forwardRef19(
@@ -3391,8 +3527,8 @@ var Reality = forwardRef19(
3391
3527
  } = inProps;
3392
3528
  const ctxRef = useRef16(null);
3393
3529
  const creationId = useRef16(0);
3394
- const [isReady, setIsReady] = useState7(false);
3395
- const cleanupReality = useCallback8(() => {
3530
+ const [isReady, setIsReady] = useState8(false);
3531
+ const cleanupReality = useCallback9(() => {
3396
3532
  ctxRef.current?.attachmentRegistry.destroy();
3397
3533
  ctxRef.current?.resourceRegistry.destroy();
3398
3534
  ctxRef.current?.reality.destroy();
@@ -3405,7 +3541,7 @@ var Reality = forwardRef19(
3405
3541
  cleanupReality();
3406
3542
  };
3407
3543
  }, [cleanupReality]);
3408
- const createReality = useCallback8(async () => {
3544
+ const createReality = useCallback9(async () => {
3409
3545
  const id = ++creationId.current;
3410
3546
  const resourceRegistry = new ResourceRegistry();
3411
3547
  const attachmentRegistry = new AttachmentRegistry();
@@ -3448,7 +3584,7 @@ var Reality = forwardRef19(
3448
3584
  return null;
3449
3585
  }
3450
3586
  }, [cleanupReality]);
3451
- const content = useCallback8(() => /* @__PURE__ */ jsx22(Fragment3, {}), []);
3587
+ const content = useCallback9(() => /* @__PURE__ */ jsx22(Fragment3, {}), []);
3452
3588
  useRealityEvents({
3453
3589
  instance: ctxRef.current?.reality ?? null,
3454
3590
  onSpatialTap,
@@ -3477,7 +3613,7 @@ var Reality = forwardRef19(
3477
3613
  );
3478
3614
 
3479
3615
  // src/reality/components/AttachmentAsset.tsx
3480
- import { useEffect as useEffect27, useState as useState8 } from "react";
3616
+ import { useEffect as useEffect27, useState as useState9 } from "react";
3481
3617
  import { createPortal as createPortal3 } from "react-dom";
3482
3618
  import { jsx as jsx23 } from "react/jsx-runtime";
3483
3619
  var AttachmentAsset = ({
@@ -3485,7 +3621,7 @@ var AttachmentAsset = ({
3485
3621
  children
3486
3622
  }) => {
3487
3623
  const ctx = useRealityContext();
3488
- const [containers, setContainers] = useState8([]);
3624
+ const [containers, setContainers] = useState9([]);
3489
3625
  useEffect27(() => {
3490
3626
  if (!ctx) return;
3491
3627
  return ctx.attachmentRegistry.onContainersChange(name, setContainers);
@@ -3497,7 +3633,7 @@ var AttachmentAsset = ({
3497
3633
  };
3498
3634
 
3499
3635
  // src/reality/components/AttachmentEntity.tsx
3500
- import { useEffect as useEffect28, useRef as useRef17, useState as useState9 } from "react";
3636
+ import { useEffect as useEffect28, useRef as useRef17, useState as useState10 } from "react";
3501
3637
  var instanceCounter = 0;
3502
3638
  var AttachmentEntity = ({
3503
3639
  attachment: attachmentName,
@@ -3510,7 +3646,7 @@ var AttachmentEntity = ({
3510
3646
  const parentIdRef = useRef17(null);
3511
3647
  const instanceIdRef = useRef17(`att_${++instanceCounter}`);
3512
3648
  const attachmentNameRef = useRef17(attachmentName);
3513
- const [childWindow, setChildWindow] = useState9(null);
3649
+ const [childWindow, setChildWindow] = useState10(null);
3514
3650
  useEffect28(() => {
3515
3651
  if (!ctx || !parent) return;
3516
3652
  if (attachmentRef.current) return;
@@ -3724,7 +3860,7 @@ async function convertCoordinate(position, { from, to }) {
3724
3860
  }
3725
3861
 
3726
3862
  // src/index.ts
3727
- var version = "1.5.0";
3863
+ var version = "1.6.0";
3728
3864
  if (typeof window !== "undefined") {
3729
3865
  initPolyfill();
3730
3866
  }