@liveroom-tech/react-immersive 1.0.1 → 1.0.2
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/README.md +3 -1
- package/dist/index.d.mts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +146 -0
- package/dist/index.mjs +145 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1018,6 +1018,8 @@ Example:
|
|
|
1018
1018
|
/>
|
|
1019
1019
|
```
|
|
1020
1020
|
|
|
1021
|
+
Passing an explicit `camera` counts as choosing the initial view yourself, so the mount-time auto-fit (see [`onAutoFit`](#onautofit)) is skipped automatically and your `position`/`fov` stick. Provide `onAutoFit` as well only if you want to run your _own_ fit-to-scene logic instead.
|
|
1022
|
+
|
|
1021
1023
|
### `backgroundColor`
|
|
1022
1024
|
|
|
1023
1025
|
Optional background color for the viewer canvas.
|
|
@@ -1273,7 +1275,7 @@ true;
|
|
|
1273
1275
|
|
|
1274
1276
|
### `onAutoFit`
|
|
1275
1277
|
|
|
1276
|
-
Optional async callback fired once the model has loaded and the scene is ready. When provided, the viewer calls it so consumers can run their own fit-to-scene behavior (e.g. an animated fit); if omitted, the viewer falls back to its internal `fitScene
|
|
1278
|
+
Optional async callback fired once the model has loaded and the scene is ready. When provided, the viewer calls it so consumers can run their own fit-to-scene behavior (e.g. an animated fit); if omitted, the viewer falls back to its internal `fitScene` — unless an explicit [`camera`](#camera) prop was given, in which case that position is treated as the chosen initial view and `fitScene` is skipped.
|
|
1277
1279
|
|
|
1278
1280
|
Current callback shape:
|
|
1279
1281
|
|
package/dist/index.d.mts
CHANGED
|
@@ -669,4 +669,22 @@ type ViewerActionsProps = {
|
|
|
669
669
|
};
|
|
670
670
|
declare function useViewerActions(objectBindings: Record<string, ObjectBinding>, options?: ViewerActionsOptions): ViewerActionsProps;
|
|
671
671
|
|
|
672
|
-
|
|
672
|
+
type UseShareableViewerStateOptions = {
|
|
673
|
+
cameraState: ViewerCameraState | null;
|
|
674
|
+
setCameraState: (state: ViewerCameraState, enableTransition?: boolean) => Promise<boolean>;
|
|
675
|
+
objectBindings: Record<string, ObjectBinding>;
|
|
676
|
+
onObjectBindingsChange: (next: Record<string, ObjectBinding>) => void;
|
|
677
|
+
selectedObjectBinding: ObjectBinding | null;
|
|
678
|
+
setSelectedObjectBinding: (binding: ObjectBinding | null) => void;
|
|
679
|
+
paramKey?: string;
|
|
680
|
+
debounceMs?: number;
|
|
681
|
+
autoSync?: boolean;
|
|
682
|
+
};
|
|
683
|
+
type ShareableViewerStateProps = {
|
|
684
|
+
getShareUrl: () => string;
|
|
685
|
+
syncUrl: () => void;
|
|
686
|
+
restoreFromUrl: () => Promise<boolean>;
|
|
687
|
+
};
|
|
688
|
+
declare function useShareableViewerState({ cameraState, setCameraState, objectBindings, onObjectBindingsChange, selectedObjectBinding, setSelectedObjectBinding, paramKey, debounceMs, autoSync, }: UseShareableViewerStateOptions): ShareableViewerStateProps;
|
|
689
|
+
|
|
690
|
+
export { type AnimationClipInfo, type AnimationControls, type AnimationLoopMode, type AnimationPlaybackState, BindingBuilder, type CaptureImageOptions, type CustomObjectBindingDataPanelProps, type CustomSceneObjectsPanelProps, type HiddenObjectsState, type HomeCameraState, MATERIAL_BLENDING_MODES, MATERIAL_SIDES, ModelViewer, type ModelViewerProps, type ObjectActionEvent, type ObjectBinding, type ObjectBindingAction, type ObjectBindingMaterial, type ObjectBindingMaterialBlendingMode, type ObjectBindingMaterialSide, type ObjectBindingTextureSlot, type ObjectVisibilityProps, type SceneAnimationClipConfig, type SceneAnimationConfig, type SceneConfig, SimpleModelViewer, type SimpleModelViewerProps, type ViewerActionsOptions, type ViewerActionsProps, type ViewerAnimationsProps, type ViewerCameraProps, type ViewerCameraState, type ViewerModelBounds, type ViewerModelProps, type ViewerReadyState, type ViewerSelectionProps, useObjectBinding, useObjectBindingIds, useObjectVisibility, useShareableViewerState, useViewerActions, useViewerAnimations, useViewerCamera, useViewerHover, useViewerModel, useViewerSelection };
|
package/dist/index.d.ts
CHANGED
|
@@ -669,4 +669,22 @@ type ViewerActionsProps = {
|
|
|
669
669
|
};
|
|
670
670
|
declare function useViewerActions(objectBindings: Record<string, ObjectBinding>, options?: ViewerActionsOptions): ViewerActionsProps;
|
|
671
671
|
|
|
672
|
-
|
|
672
|
+
type UseShareableViewerStateOptions = {
|
|
673
|
+
cameraState: ViewerCameraState | null;
|
|
674
|
+
setCameraState: (state: ViewerCameraState, enableTransition?: boolean) => Promise<boolean>;
|
|
675
|
+
objectBindings: Record<string, ObjectBinding>;
|
|
676
|
+
onObjectBindingsChange: (next: Record<string, ObjectBinding>) => void;
|
|
677
|
+
selectedObjectBinding: ObjectBinding | null;
|
|
678
|
+
setSelectedObjectBinding: (binding: ObjectBinding | null) => void;
|
|
679
|
+
paramKey?: string;
|
|
680
|
+
debounceMs?: number;
|
|
681
|
+
autoSync?: boolean;
|
|
682
|
+
};
|
|
683
|
+
type ShareableViewerStateProps = {
|
|
684
|
+
getShareUrl: () => string;
|
|
685
|
+
syncUrl: () => void;
|
|
686
|
+
restoreFromUrl: () => Promise<boolean>;
|
|
687
|
+
};
|
|
688
|
+
declare function useShareableViewerState({ cameraState, setCameraState, objectBindings, onObjectBindingsChange, selectedObjectBinding, setSelectedObjectBinding, paramKey, debounceMs, autoSync, }: UseShareableViewerStateOptions): ShareableViewerStateProps;
|
|
689
|
+
|
|
690
|
+
export { type AnimationClipInfo, type AnimationControls, type AnimationLoopMode, type AnimationPlaybackState, BindingBuilder, type CaptureImageOptions, type CustomObjectBindingDataPanelProps, type CustomSceneObjectsPanelProps, type HiddenObjectsState, type HomeCameraState, MATERIAL_BLENDING_MODES, MATERIAL_SIDES, ModelViewer, type ModelViewerProps, type ObjectActionEvent, type ObjectBinding, type ObjectBindingAction, type ObjectBindingMaterial, type ObjectBindingMaterialBlendingMode, type ObjectBindingMaterialSide, type ObjectBindingTextureSlot, type ObjectVisibilityProps, type SceneAnimationClipConfig, type SceneAnimationConfig, type SceneConfig, SimpleModelViewer, type SimpleModelViewerProps, type ViewerActionsOptions, type ViewerActionsProps, type ViewerAnimationsProps, type ViewerCameraProps, type ViewerCameraState, type ViewerModelBounds, type ViewerModelProps, type ViewerReadyState, type ViewerSelectionProps, useObjectBinding, useObjectBindingIds, useObjectVisibility, useShareableViewerState, useViewerActions, useViewerAnimations, useViewerCamera, useViewerHover, useViewerModel, useViewerSelection };
|
package/dist/index.js
CHANGED
|
@@ -38,6 +38,7 @@ __export(index_exports, {
|
|
|
38
38
|
useObjectBinding: () => useObjectBinding,
|
|
39
39
|
useObjectBindingIds: () => useObjectBindingIds,
|
|
40
40
|
useObjectVisibility: () => useObjectVisibility,
|
|
41
|
+
useShareableViewerState: () => useShareableViewerState,
|
|
41
42
|
useViewerActions: () => useViewerActions,
|
|
42
43
|
useViewerAnimations: () => useViewerAnimations,
|
|
43
44
|
useViewerCamera: () => useViewerCamera,
|
|
@@ -15895,6 +15896,150 @@ function useViewerActions(objectBindings, options = {}) {
|
|
|
15895
15896
|
runAction
|
|
15896
15897
|
};
|
|
15897
15898
|
}
|
|
15899
|
+
|
|
15900
|
+
// src/hooks/useShareableViewerState.ts
|
|
15901
|
+
var import_react46 = require("react");
|
|
15902
|
+
function serializeState(cameraState, objectBindings, selectedObjectBinding) {
|
|
15903
|
+
const hidden = Object.values(objectBindings).filter((binding) => binding.visible === false).map((binding) => binding.id);
|
|
15904
|
+
return {
|
|
15905
|
+
camera: cameraState ?? void 0,
|
|
15906
|
+
hidden,
|
|
15907
|
+
selected: selectedObjectBinding?.id ?? null
|
|
15908
|
+
};
|
|
15909
|
+
}
|
|
15910
|
+
function useShareableViewerState({
|
|
15911
|
+
cameraState,
|
|
15912
|
+
setCameraState,
|
|
15913
|
+
objectBindings,
|
|
15914
|
+
onObjectBindingsChange,
|
|
15915
|
+
selectedObjectBinding,
|
|
15916
|
+
setSelectedObjectBinding,
|
|
15917
|
+
paramKey = "view",
|
|
15918
|
+
debounceMs = 400,
|
|
15919
|
+
autoSync = true
|
|
15920
|
+
}) {
|
|
15921
|
+
const lastWrittenRawRef = (0, import_react46.useRef)(null);
|
|
15922
|
+
const buildHash = (0, import_react46.useCallback)(() => {
|
|
15923
|
+
const state = serializeState(
|
|
15924
|
+
cameraState,
|
|
15925
|
+
objectBindings,
|
|
15926
|
+
selectedObjectBinding
|
|
15927
|
+
);
|
|
15928
|
+
return `${paramKey}=${encodeURIComponent(JSON.stringify(state))}`;
|
|
15929
|
+
}, [cameraState, objectBindings, selectedObjectBinding, paramKey]);
|
|
15930
|
+
const getShareUrl = (0, import_react46.useCallback)(() => {
|
|
15931
|
+
const url = new URL(window.location.href);
|
|
15932
|
+
url.hash = buildHash();
|
|
15933
|
+
return url.toString();
|
|
15934
|
+
}, [buildHash]);
|
|
15935
|
+
const syncUrl = (0, import_react46.useCallback)(() => {
|
|
15936
|
+
const url = new URL(window.location.href);
|
|
15937
|
+
url.hash = buildHash();
|
|
15938
|
+
window.history.replaceState(null, "", url.toString());
|
|
15939
|
+
lastWrittenRawRef.current = new URLSearchParams(url.hash.slice(1)).get(
|
|
15940
|
+
paramKey
|
|
15941
|
+
);
|
|
15942
|
+
}, [buildHash, paramKey]);
|
|
15943
|
+
const latestStateRef = (0, import_react46.useRef)({
|
|
15944
|
+
cameraState,
|
|
15945
|
+
objectBindings,
|
|
15946
|
+
selectedObjectBinding
|
|
15947
|
+
});
|
|
15948
|
+
latestStateRef.current = {
|
|
15949
|
+
cameraState,
|
|
15950
|
+
objectBindings,
|
|
15951
|
+
selectedObjectBinding
|
|
15952
|
+
};
|
|
15953
|
+
const [restoreAttempted, setRestoreAttempted] = (0, import_react46.useState)(false);
|
|
15954
|
+
const lastSyncedHashRef = (0, import_react46.useRef)(null);
|
|
15955
|
+
(0, import_react46.useEffect)(() => {
|
|
15956
|
+
if (!autoSync || !restoreAttempted) return;
|
|
15957
|
+
const tick = () => {
|
|
15958
|
+
const current = latestStateRef.current;
|
|
15959
|
+
const state = serializeState(
|
|
15960
|
+
current.cameraState,
|
|
15961
|
+
current.objectBindings,
|
|
15962
|
+
current.selectedObjectBinding
|
|
15963
|
+
);
|
|
15964
|
+
const hash = `${paramKey}=${encodeURIComponent(JSON.stringify(state))}`;
|
|
15965
|
+
if (hash === lastSyncedHashRef.current) return;
|
|
15966
|
+
lastSyncedHashRef.current = hash;
|
|
15967
|
+
const url = new URL(window.location.href);
|
|
15968
|
+
url.hash = hash;
|
|
15969
|
+
window.history.replaceState(null, "", url.toString());
|
|
15970
|
+
lastWrittenRawRef.current = new URLSearchParams(url.hash.slice(1)).get(
|
|
15971
|
+
paramKey
|
|
15972
|
+
);
|
|
15973
|
+
};
|
|
15974
|
+
const id = window.setInterval(tick, debounceMs);
|
|
15975
|
+
return () => window.clearInterval(id);
|
|
15976
|
+
}, [autoSync, restoreAttempted, debounceMs, paramKey]);
|
|
15977
|
+
const lastRestoredRawRef = (0, import_react46.useRef)(null);
|
|
15978
|
+
const restoringRawRef = (0, import_react46.useRef)(null);
|
|
15979
|
+
const restoreFromUrl = (0, import_react46.useCallback)(async () => {
|
|
15980
|
+
setRestoreAttempted(true);
|
|
15981
|
+
const rawHash = window.location.hash.startsWith("#") ? window.location.hash.slice(1) : window.location.hash;
|
|
15982
|
+
const raw = new URLSearchParams(rawHash).get(paramKey);
|
|
15983
|
+
if (!raw) {
|
|
15984
|
+
lastRestoredRawRef.current = null;
|
|
15985
|
+
return false;
|
|
15986
|
+
}
|
|
15987
|
+
if (raw === lastWrittenRawRef.current || raw === lastRestoredRawRef.current || raw === restoringRawRef.current) {
|
|
15988
|
+
return false;
|
|
15989
|
+
}
|
|
15990
|
+
let state;
|
|
15991
|
+
try {
|
|
15992
|
+
state = JSON.parse(raw);
|
|
15993
|
+
} catch {
|
|
15994
|
+
return false;
|
|
15995
|
+
}
|
|
15996
|
+
restoringRawRef.current = raw;
|
|
15997
|
+
try {
|
|
15998
|
+
if (state.camera) {
|
|
15999
|
+
await setCameraState(state.camera, false);
|
|
16000
|
+
}
|
|
16001
|
+
if (state.hidden) {
|
|
16002
|
+
const hiddenIds = new Set(state.hidden);
|
|
16003
|
+
onObjectBindingsChange(
|
|
16004
|
+
Object.fromEntries(
|
|
16005
|
+
Object.entries(objectBindings).map(([bindingKey, binding]) => [
|
|
16006
|
+
bindingKey,
|
|
16007
|
+
{ ...binding, visible: !hiddenIds.has(binding.id) }
|
|
16008
|
+
])
|
|
16009
|
+
)
|
|
16010
|
+
);
|
|
16011
|
+
}
|
|
16012
|
+
if (state.selected !== void 0) {
|
|
16013
|
+
const bindingKey = state.selected ? resolveBindingKey(objectBindings, state.selected) : null;
|
|
16014
|
+
setSelectedObjectBinding(
|
|
16015
|
+
bindingKey ? objectBindings[bindingKey] : null
|
|
16016
|
+
);
|
|
16017
|
+
}
|
|
16018
|
+
lastRestoredRawRef.current = raw;
|
|
16019
|
+
return true;
|
|
16020
|
+
} finally {
|
|
16021
|
+
if (restoringRawRef.current === raw) {
|
|
16022
|
+
restoringRawRef.current = null;
|
|
16023
|
+
}
|
|
16024
|
+
}
|
|
16025
|
+
}, [
|
|
16026
|
+
objectBindings,
|
|
16027
|
+
onObjectBindingsChange,
|
|
16028
|
+
paramKey,
|
|
16029
|
+
setCameraState,
|
|
16030
|
+
setSelectedObjectBinding
|
|
16031
|
+
]);
|
|
16032
|
+
(0, import_react46.useEffect)(() => {
|
|
16033
|
+
const handleHashChange = () => {
|
|
16034
|
+
void restoreFromUrl();
|
|
16035
|
+
};
|
|
16036
|
+
window.addEventListener("hashchange", handleHashChange);
|
|
16037
|
+
return () => {
|
|
16038
|
+
window.removeEventListener("hashchange", handleHashChange);
|
|
16039
|
+
};
|
|
16040
|
+
}, [restoreFromUrl]);
|
|
16041
|
+
return { getShareUrl, syncUrl, restoreFromUrl };
|
|
16042
|
+
}
|
|
15898
16043
|
// Annotate the CommonJS export names for ESM import in node:
|
|
15899
16044
|
0 && (module.exports = {
|
|
15900
16045
|
BindingBuilder,
|
|
@@ -15905,6 +16050,7 @@ function useViewerActions(objectBindings, options = {}) {
|
|
|
15905
16050
|
useObjectBinding,
|
|
15906
16051
|
useObjectBindingIds,
|
|
15907
16052
|
useObjectVisibility,
|
|
16053
|
+
useShareableViewerState,
|
|
15908
16054
|
useViewerActions,
|
|
15909
16055
|
useViewerAnimations,
|
|
15910
16056
|
useViewerCamera,
|
package/dist/index.mjs
CHANGED
|
@@ -15991,6 +15991,150 @@ function useViewerActions(objectBindings, options = {}) {
|
|
|
15991
15991
|
runAction
|
|
15992
15992
|
};
|
|
15993
15993
|
}
|
|
15994
|
+
|
|
15995
|
+
// src/hooks/useShareableViewerState.ts
|
|
15996
|
+
import { useCallback as useCallback15, useEffect as useEffect20, useRef as useRef18, useState as useState29 } from "react";
|
|
15997
|
+
function serializeState(cameraState, objectBindings, selectedObjectBinding) {
|
|
15998
|
+
const hidden = Object.values(objectBindings).filter((binding) => binding.visible === false).map((binding) => binding.id);
|
|
15999
|
+
return {
|
|
16000
|
+
camera: cameraState ?? void 0,
|
|
16001
|
+
hidden,
|
|
16002
|
+
selected: selectedObjectBinding?.id ?? null
|
|
16003
|
+
};
|
|
16004
|
+
}
|
|
16005
|
+
function useShareableViewerState({
|
|
16006
|
+
cameraState,
|
|
16007
|
+
setCameraState,
|
|
16008
|
+
objectBindings,
|
|
16009
|
+
onObjectBindingsChange,
|
|
16010
|
+
selectedObjectBinding,
|
|
16011
|
+
setSelectedObjectBinding,
|
|
16012
|
+
paramKey = "view",
|
|
16013
|
+
debounceMs = 400,
|
|
16014
|
+
autoSync = true
|
|
16015
|
+
}) {
|
|
16016
|
+
const lastWrittenRawRef = useRef18(null);
|
|
16017
|
+
const buildHash = useCallback15(() => {
|
|
16018
|
+
const state = serializeState(
|
|
16019
|
+
cameraState,
|
|
16020
|
+
objectBindings,
|
|
16021
|
+
selectedObjectBinding
|
|
16022
|
+
);
|
|
16023
|
+
return `${paramKey}=${encodeURIComponent(JSON.stringify(state))}`;
|
|
16024
|
+
}, [cameraState, objectBindings, selectedObjectBinding, paramKey]);
|
|
16025
|
+
const getShareUrl = useCallback15(() => {
|
|
16026
|
+
const url = new URL(window.location.href);
|
|
16027
|
+
url.hash = buildHash();
|
|
16028
|
+
return url.toString();
|
|
16029
|
+
}, [buildHash]);
|
|
16030
|
+
const syncUrl = useCallback15(() => {
|
|
16031
|
+
const url = new URL(window.location.href);
|
|
16032
|
+
url.hash = buildHash();
|
|
16033
|
+
window.history.replaceState(null, "", url.toString());
|
|
16034
|
+
lastWrittenRawRef.current = new URLSearchParams(url.hash.slice(1)).get(
|
|
16035
|
+
paramKey
|
|
16036
|
+
);
|
|
16037
|
+
}, [buildHash, paramKey]);
|
|
16038
|
+
const latestStateRef = useRef18({
|
|
16039
|
+
cameraState,
|
|
16040
|
+
objectBindings,
|
|
16041
|
+
selectedObjectBinding
|
|
16042
|
+
});
|
|
16043
|
+
latestStateRef.current = {
|
|
16044
|
+
cameraState,
|
|
16045
|
+
objectBindings,
|
|
16046
|
+
selectedObjectBinding
|
|
16047
|
+
};
|
|
16048
|
+
const [restoreAttempted, setRestoreAttempted] = useState29(false);
|
|
16049
|
+
const lastSyncedHashRef = useRef18(null);
|
|
16050
|
+
useEffect20(() => {
|
|
16051
|
+
if (!autoSync || !restoreAttempted) return;
|
|
16052
|
+
const tick = () => {
|
|
16053
|
+
const current = latestStateRef.current;
|
|
16054
|
+
const state = serializeState(
|
|
16055
|
+
current.cameraState,
|
|
16056
|
+
current.objectBindings,
|
|
16057
|
+
current.selectedObjectBinding
|
|
16058
|
+
);
|
|
16059
|
+
const hash = `${paramKey}=${encodeURIComponent(JSON.stringify(state))}`;
|
|
16060
|
+
if (hash === lastSyncedHashRef.current) return;
|
|
16061
|
+
lastSyncedHashRef.current = hash;
|
|
16062
|
+
const url = new URL(window.location.href);
|
|
16063
|
+
url.hash = hash;
|
|
16064
|
+
window.history.replaceState(null, "", url.toString());
|
|
16065
|
+
lastWrittenRawRef.current = new URLSearchParams(url.hash.slice(1)).get(
|
|
16066
|
+
paramKey
|
|
16067
|
+
);
|
|
16068
|
+
};
|
|
16069
|
+
const id = window.setInterval(tick, debounceMs);
|
|
16070
|
+
return () => window.clearInterval(id);
|
|
16071
|
+
}, [autoSync, restoreAttempted, debounceMs, paramKey]);
|
|
16072
|
+
const lastRestoredRawRef = useRef18(null);
|
|
16073
|
+
const restoringRawRef = useRef18(null);
|
|
16074
|
+
const restoreFromUrl = useCallback15(async () => {
|
|
16075
|
+
setRestoreAttempted(true);
|
|
16076
|
+
const rawHash = window.location.hash.startsWith("#") ? window.location.hash.slice(1) : window.location.hash;
|
|
16077
|
+
const raw = new URLSearchParams(rawHash).get(paramKey);
|
|
16078
|
+
if (!raw) {
|
|
16079
|
+
lastRestoredRawRef.current = null;
|
|
16080
|
+
return false;
|
|
16081
|
+
}
|
|
16082
|
+
if (raw === lastWrittenRawRef.current || raw === lastRestoredRawRef.current || raw === restoringRawRef.current) {
|
|
16083
|
+
return false;
|
|
16084
|
+
}
|
|
16085
|
+
let state;
|
|
16086
|
+
try {
|
|
16087
|
+
state = JSON.parse(raw);
|
|
16088
|
+
} catch {
|
|
16089
|
+
return false;
|
|
16090
|
+
}
|
|
16091
|
+
restoringRawRef.current = raw;
|
|
16092
|
+
try {
|
|
16093
|
+
if (state.camera) {
|
|
16094
|
+
await setCameraState(state.camera, false);
|
|
16095
|
+
}
|
|
16096
|
+
if (state.hidden) {
|
|
16097
|
+
const hiddenIds = new Set(state.hidden);
|
|
16098
|
+
onObjectBindingsChange(
|
|
16099
|
+
Object.fromEntries(
|
|
16100
|
+
Object.entries(objectBindings).map(([bindingKey, binding]) => [
|
|
16101
|
+
bindingKey,
|
|
16102
|
+
{ ...binding, visible: !hiddenIds.has(binding.id) }
|
|
16103
|
+
])
|
|
16104
|
+
)
|
|
16105
|
+
);
|
|
16106
|
+
}
|
|
16107
|
+
if (state.selected !== void 0) {
|
|
16108
|
+
const bindingKey = state.selected ? resolveBindingKey(objectBindings, state.selected) : null;
|
|
16109
|
+
setSelectedObjectBinding(
|
|
16110
|
+
bindingKey ? objectBindings[bindingKey] : null
|
|
16111
|
+
);
|
|
16112
|
+
}
|
|
16113
|
+
lastRestoredRawRef.current = raw;
|
|
16114
|
+
return true;
|
|
16115
|
+
} finally {
|
|
16116
|
+
if (restoringRawRef.current === raw) {
|
|
16117
|
+
restoringRawRef.current = null;
|
|
16118
|
+
}
|
|
16119
|
+
}
|
|
16120
|
+
}, [
|
|
16121
|
+
objectBindings,
|
|
16122
|
+
onObjectBindingsChange,
|
|
16123
|
+
paramKey,
|
|
16124
|
+
setCameraState,
|
|
16125
|
+
setSelectedObjectBinding
|
|
16126
|
+
]);
|
|
16127
|
+
useEffect20(() => {
|
|
16128
|
+
const handleHashChange = () => {
|
|
16129
|
+
void restoreFromUrl();
|
|
16130
|
+
};
|
|
16131
|
+
window.addEventListener("hashchange", handleHashChange);
|
|
16132
|
+
return () => {
|
|
16133
|
+
window.removeEventListener("hashchange", handleHashChange);
|
|
16134
|
+
};
|
|
16135
|
+
}, [restoreFromUrl]);
|
|
16136
|
+
return { getShareUrl, syncUrl, restoreFromUrl };
|
|
16137
|
+
}
|
|
15994
16138
|
export {
|
|
15995
16139
|
BindingBuilder,
|
|
15996
16140
|
MATERIAL_BLENDING_MODES,
|
|
@@ -16000,6 +16144,7 @@ export {
|
|
|
16000
16144
|
useObjectBinding,
|
|
16001
16145
|
useObjectBindingIds,
|
|
16002
16146
|
useObjectVisibility,
|
|
16147
|
+
useShareableViewerState,
|
|
16003
16148
|
useViewerActions,
|
|
16004
16149
|
useViewerAnimations,
|
|
16005
16150
|
useViewerCamera,
|