New: Store the editorOpen state in Theatre
This commit is contained in:
parent
08759e2d5c
commit
6ac6aa87d7
4 changed files with 56 additions and 94 deletions
|
@ -1,4 +1,5 @@
|
||||||
import type {VFC} from 'react'
|
import type {VFC} from 'react'
|
||||||
|
import {useLayoutEffect} from 'react'
|
||||||
import React, {useEffect, useRef, Suspense} from 'react'
|
import React, {useEffect, useRef, Suspense} from 'react'
|
||||||
import {Canvas} from '@react-three/fiber'
|
import {Canvas} from '@react-three/fiber'
|
||||||
import {useEditorStore} from '../store'
|
import {useEditorStore} from '../store'
|
||||||
|
@ -8,8 +9,9 @@ import root from 'react-shadow'
|
||||||
import styles from '../bundle.css.txt'
|
import styles from '../bundle.css.txt'
|
||||||
import UI from './UI'
|
import UI from './UI'
|
||||||
import ProxyManager from './ProxyManager'
|
import ProxyManager from './ProxyManager'
|
||||||
import {Button, Heading, Code, PortalManager, IdProvider} from './elements'
|
import {Button, PortalManager, IdProvider} from './elements'
|
||||||
import studio from '@theatre/studio'
|
import studio from '@theatre/studio'
|
||||||
|
import {useVal} from '@theatre/dataverse-react'
|
||||||
|
|
||||||
const EditorScene = () => {
|
const EditorScene = () => {
|
||||||
const orbitControlsRef = useRef<typeof OrbitControls>()
|
const orbitControlsRef = useRef<typeof OrbitControls>()
|
||||||
|
@ -60,25 +62,26 @@ const EditorScene = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Editor: VFC = () => {
|
const Editor: VFC = () => {
|
||||||
const [
|
const [editorObject, sceneSnapshot, initialEditorCamera, createSnapshot] =
|
||||||
sceneSnapshot,
|
useEditorStore(
|
||||||
editorOpen,
|
|
||||||
initialState,
|
|
||||||
initialEditorCamera,
|
|
||||||
setEditorOpen,
|
|
||||||
createSnapshot,
|
|
||||||
] = useEditorStore(
|
|
||||||
(state) => [
|
(state) => [
|
||||||
|
state.editorObject,
|
||||||
state.sceneSnapshot,
|
state.sceneSnapshot,
|
||||||
state.editorOpen,
|
|
||||||
state.initialState,
|
|
||||||
state.initialEditorCamera,
|
state.initialEditorCamera,
|
||||||
state.setEditorOpen,
|
|
||||||
state.createSnapshot,
|
state.createSnapshot,
|
||||||
],
|
],
|
||||||
shallow,
|
shallow,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const editorOpen = !!useVal(editorObject?.props._isOpen)
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (editorOpen) {
|
||||||
|
createSnapshot()
|
||||||
|
}
|
||||||
|
}, [editorOpen])
|
||||||
|
|
||||||
|
if (!editorObject) return <></>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<root.div>
|
<root.div>
|
||||||
<div id="react-three-editable-editor-root">
|
<div id="react-three-editable-editor-root">
|
||||||
|
@ -110,67 +113,15 @@ const Editor: VFC = () => {
|
||||||
|
|
||||||
<UI />
|
<UI />
|
||||||
</>
|
</>
|
||||||
) : (
|
) : null}
|
||||||
<div className="flex justify-center items-center bg-white h-screen">
|
|
||||||
<div className="flex flex-col gap-5 items-center ">
|
|
||||||
<Heading className="text-2xl mb-4">
|
|
||||||
No canvas connected
|
|
||||||
</Heading>
|
|
||||||
<div>
|
|
||||||
Please use <Code>configure()</Code> and{' '}
|
|
||||||
<Code>bind()</Code> to connect a canvas to React Three
|
|
||||||
Editable.
|
|
||||||
</div>
|
|
||||||
<Code block>
|
|
||||||
{`import React from 'react';
|
|
||||||
import { Canvas } from '@react-three/fiber';
|
|
||||||
import { configure, editable as e } from 'react-three-editable';
|
|
||||||
|
|
||||||
const bind = configure({
|
|
||||||
localStorageNamespace: "MyProject"
|
|
||||||
});
|
|
||||||
|
|
||||||
const MyComponent = () => (
|
|
||||||
<Canvas onCreated={bind()}>
|
|
||||||
<e.mesh uniqueName="My First Editable Object">
|
|
||||||
<sphereBufferGeometry />
|
|
||||||
<meshStandardMaterial color="rebeccapurple" />
|
|
||||||
</e.mesh>
|
|
||||||
</Canvas>
|
|
||||||
);`}
|
|
||||||
</Code>
|
|
||||||
<div>
|
|
||||||
For more details, please consult the{' '}
|
|
||||||
<a
|
|
||||||
className="rounded-md font-medium text-green-600 hover:text-green-500"
|
|
||||||
href="https://github.com/AndrewPrifer/react-three-editable"
|
|
||||||
rel="noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
documentation
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
className=""
|
|
||||||
onClick={() => {
|
|
||||||
setEditorOpen(false)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Close
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{editorOpen || (
|
{editorOpen || (
|
||||||
<Button
|
<Button
|
||||||
className="fixed bottom-5 left-5"
|
className="fixed bottom-5 left-5"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!sceneSnapshot) {
|
studio.transaction(({set}) => {
|
||||||
createSnapshot()
|
set(editorObject.props._isOpen, 1)
|
||||||
}
|
})
|
||||||
setEditorOpen(true)
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Editor
|
Editor
|
||||||
|
|
|
@ -145,10 +145,11 @@ const ProxyManager: VFC<ProxyManagerProps> = ({orbitControlsRef}) => {
|
||||||
setRenderMaterials(renderMaterials)
|
setRenderMaterials(renderMaterials)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
Object.entries(renderMaterials).forEach(([id, material]) => {
|
// @todo do we need this cleanup?
|
||||||
;(sceneProxy.getObjectById(Number.parseInt(id)) as Mesh).material =
|
// Object.entries(renderMaterials).forEach(([id, material]) => {
|
||||||
material
|
// ;(sceneProxy.getObjectById(Number.parseInt(id)) as Mesh).material =
|
||||||
})
|
// material
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
}, [sceneProxy])
|
}, [sceneProxy])
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,11 @@ import {Vector3} from 'three'
|
||||||
import {IconButton, Button, SettingsButton} from './elements'
|
import {IconButton, Button, SettingsButton} from './elements'
|
||||||
import ViewportSettings from './ViewportSettings'
|
import ViewportSettings from './ViewportSettings'
|
||||||
import type {$FixMe} from '@theatre/shared/utils/types'
|
import type {$FixMe} from '@theatre/shared/utils/types'
|
||||||
|
import studio from '@theatre/studio'
|
||||||
|
|
||||||
const UI: VFC = () => {
|
const UI: VFC = () => {
|
||||||
const [
|
const [
|
||||||
|
editorObject,
|
||||||
transformControlsMode,
|
transformControlsMode,
|
||||||
transformControlsSpace,
|
transformControlsSpace,
|
||||||
viewportShading,
|
viewportShading,
|
||||||
|
@ -21,9 +23,9 @@ const UI: VFC = () => {
|
||||||
setTransformControlsMode,
|
setTransformControlsMode,
|
||||||
setTransformControlsSpace,
|
setTransformControlsSpace,
|
||||||
setViewportShading,
|
setViewportShading,
|
||||||
setEditorOpen,
|
|
||||||
] = useEditorStore(
|
] = useEditorStore(
|
||||||
(state) => [
|
(state) => [
|
||||||
|
state.editorObject,
|
||||||
state.transformControlsMode,
|
state.transformControlsMode,
|
||||||
state.transformControlsSpace,
|
state.transformControlsSpace,
|
||||||
state.viewportShading,
|
state.viewportShading,
|
||||||
|
@ -31,11 +33,12 @@ const UI: VFC = () => {
|
||||||
state.setTransformControlsMode,
|
state.setTransformControlsMode,
|
||||||
state.setTransformControlsSpace,
|
state.setTransformControlsSpace,
|
||||||
state.setViewportShading,
|
state.setViewportShading,
|
||||||
state.setEditorOpen,
|
|
||||||
],
|
],
|
||||||
shallow,
|
shallow,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!editorObject) return <></>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="absolute inset-0 z-50 pointer-events-none">
|
<div className="absolute inset-0 z-50 pointer-events-none">
|
||||||
<div className="flex h-full">
|
<div className="flex h-full">
|
||||||
|
@ -134,7 +137,11 @@ const UI: VFC = () => {
|
||||||
{/* Bottom-left corner*/}
|
{/* Bottom-left corner*/}
|
||||||
<Button
|
<Button
|
||||||
className="absolute left-0 bottom-0 pointer-events-auto"
|
className="absolute left-0 bottom-0 pointer-events-auto"
|
||||||
onClick={() => setEditorOpen(false)}
|
onClick={() =>
|
||||||
|
studio.transaction(({set}) => {
|
||||||
|
set(editorObject.props._isOpen, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Close
|
Close
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -137,7 +137,7 @@ export interface EditableState {
|
||||||
|
|
||||||
export type EditorStore = {
|
export type EditorStore = {
|
||||||
sheet: ISheet | null
|
sheet: ISheet | null
|
||||||
uiSheet: ISheet | null
|
editorObject: ISheetObject<typeof editorSheetObjectConfig['props']> | null
|
||||||
sheetObjects: {[uniqueName in string]?: BaseSheetObjectType}
|
sheetObjects: {[uniqueName in string]?: BaseSheetObjectType}
|
||||||
scene: Scene | null
|
scene: Scene | null
|
||||||
gl: WebGLRenderer | null
|
gl: WebGLRenderer | null
|
||||||
|
@ -152,7 +152,6 @@ export type EditorStore = {
|
||||||
transformControlsMode: TransformControlsMode
|
transformControlsMode: TransformControlsMode
|
||||||
transformControlsSpace: TransformControlsSpace
|
transformControlsSpace: TransformControlsSpace
|
||||||
viewportShading: ViewportShading
|
viewportShading: ViewportShading
|
||||||
editorOpen: boolean
|
|
||||||
sceneSnapshot: Scene | null
|
sceneSnapshot: Scene | null
|
||||||
editablesSnapshot: Record<string, EditableSnapshot> | null
|
editablesSnapshot: Record<string, EditableSnapshot> | null
|
||||||
hdrPaths: string[]
|
hdrPaths: string[]
|
||||||
|
@ -170,7 +169,7 @@ export type EditorStore = {
|
||||||
allowImplicitInstancing: boolean,
|
allowImplicitInstancing: boolean,
|
||||||
editorCamera: ContainerProps['camera'],
|
editorCamera: ContainerProps['camera'],
|
||||||
sheet: ISheet,
|
sheet: ISheet,
|
||||||
uiSheet: null | ISheet,
|
editorObject: null | ISheetObject<typeof editorSheetObjectConfig['props']>,
|
||||||
) => void
|
) => void
|
||||||
|
|
||||||
setOrbitControlsRef: (
|
setOrbitControlsRef: (
|
||||||
|
@ -187,7 +186,6 @@ export type EditorStore = {
|
||||||
setShowGrid: (show: boolean) => void
|
setShowGrid: (show: boolean) => void
|
||||||
setShowAxes: (show: boolean) => void
|
setShowAxes: (show: boolean) => void
|
||||||
setReferenceWindowSize: (size: number) => void
|
setReferenceWindowSize: (size: number) => void
|
||||||
setEditorOpen: (open: boolean) => void
|
|
||||||
createSnapshot: () => void
|
createSnapshot: () => void
|
||||||
setSheetObject: (uniqueName: string, sheetObject: BaseSheetObjectType) => void
|
setSheetObject: (uniqueName: string, sheetObject: BaseSheetObjectType) => void
|
||||||
setSnapshotProxyObject: (
|
setSnapshotProxyObject: (
|
||||||
|
@ -214,7 +212,7 @@ const config: StateCreator<EditorStore> = (set, get) => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sheet: null,
|
sheet: null,
|
||||||
uiSheet: null,
|
editorObject: null,
|
||||||
sheetObjects: {},
|
sheetObjects: {},
|
||||||
scene: null,
|
scene: null,
|
||||||
gl: null,
|
gl: null,
|
||||||
|
@ -228,7 +226,6 @@ const config: StateCreator<EditorStore> = (set, get) => {
|
||||||
transformControlsMode: 'translate',
|
transformControlsMode: 'translate',
|
||||||
transformControlsSpace: 'world',
|
transformControlsSpace: 'world',
|
||||||
viewportShading: 'rendered',
|
viewportShading: 'rendered',
|
||||||
editorOpen: false,
|
|
||||||
sceneSnapshot: null,
|
sceneSnapshot: null,
|
||||||
editablesSnapshot: null,
|
editablesSnapshot: null,
|
||||||
hdrPaths: [],
|
hdrPaths: [],
|
||||||
|
@ -246,7 +243,7 @@ const config: StateCreator<EditorStore> = (set, get) => {
|
||||||
allowImplicitInstancing,
|
allowImplicitInstancing,
|
||||||
editorCamera,
|
editorCamera,
|
||||||
sheet,
|
sheet,
|
||||||
uiSheet,
|
editorObject,
|
||||||
) => {
|
) => {
|
||||||
set({
|
set({
|
||||||
scene,
|
scene,
|
||||||
|
@ -254,7 +251,7 @@ const config: StateCreator<EditorStore> = (set, get) => {
|
||||||
allowImplicitInstancing,
|
allowImplicitInstancing,
|
||||||
initialEditorCamera: editorCamera,
|
initialEditorCamera: editorCamera,
|
||||||
sheet,
|
sheet,
|
||||||
uiSheet,
|
editorObject,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -339,9 +336,6 @@ const config: StateCreator<EditorStore> = (set, get) => {
|
||||||
set({showAxes: show})
|
set({showAxes: show})
|
||||||
},
|
},
|
||||||
setReferenceWindowSize: (size) => set({referenceWindowSize: size}),
|
setReferenceWindowSize: (size) => set({referenceWindowSize: size}),
|
||||||
setEditorOpen: (open) => {
|
|
||||||
set({editorOpen: open})
|
|
||||||
},
|
|
||||||
createSnapshot: () => {
|
createSnapshot: () => {
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
sceneSnapshot: state.scene?.clone() ?? null,
|
sceneSnapshot: state.scene?.clone() ?? null,
|
||||||
|
@ -370,6 +364,12 @@ export type BindFunction = (options: {
|
||||||
sheet: ISheet
|
sheet: ISheet
|
||||||
}) => (options: {gl: WebGLRenderer; scene: Scene}) => void
|
}) => (options: {gl: WebGLRenderer; scene: Scene}) => void
|
||||||
|
|
||||||
|
const editorSheetObjectConfig = {
|
||||||
|
props: types.compound({
|
||||||
|
_isOpen: types.number(0),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
export const bindToCanvas: BindFunction = ({
|
export const bindToCanvas: BindFunction = ({
|
||||||
allowImplicitInstancing = false,
|
allowImplicitInstancing = false,
|
||||||
editorCamera = {},
|
editorCamera = {},
|
||||||
|
@ -380,6 +380,9 @@ export const bindToCanvas: BindFunction = ({
|
||||||
? getProject('R3F Plugin').sheet('UI')
|
? getProject('R3F Plugin').sheet('UI')
|
||||||
: null
|
: null
|
||||||
|
|
||||||
|
const editorSheetObject =
|
||||||
|
uiSheet?.object('Editor', null, editorSheetObjectConfig) || null
|
||||||
|
|
||||||
return ({gl, scene}) => {
|
return ({gl, scene}) => {
|
||||||
const init = useEditorStore.getState().init
|
const init = useEditorStore.getState().init
|
||||||
init(
|
init(
|
||||||
|
@ -388,7 +391,7 @@ export const bindToCanvas: BindFunction = ({
|
||||||
allowImplicitInstancing,
|
allowImplicitInstancing,
|
||||||
{...{position: [20, 20, 20]}, ...editorCamera},
|
{...{position: [20, 20, 20]}, ...editorCamera},
|
||||||
sheet,
|
sheet,
|
||||||
uiSheet,
|
editorSheetObject,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue