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 {useLayoutEffect} from 'react'
|
||||
import React, {useEffect, useRef, Suspense} from 'react'
|
||||
import {Canvas} from '@react-three/fiber'
|
||||
import {useEditorStore} from '../store'
|
||||
|
@ -8,8 +9,9 @@ import root from 'react-shadow'
|
|||
import styles from '../bundle.css.txt'
|
||||
import UI from './UI'
|
||||
import ProxyManager from './ProxyManager'
|
||||
import {Button, Heading, Code, PortalManager, IdProvider} from './elements'
|
||||
import {Button, PortalManager, IdProvider} from './elements'
|
||||
import studio from '@theatre/studio'
|
||||
import {useVal} from '@theatre/dataverse-react'
|
||||
|
||||
const EditorScene = () => {
|
||||
const orbitControlsRef = useRef<typeof OrbitControls>()
|
||||
|
@ -60,24 +62,25 @@ const EditorScene = () => {
|
|||
}
|
||||
|
||||
const Editor: VFC = () => {
|
||||
const [
|
||||
sceneSnapshot,
|
||||
editorOpen,
|
||||
initialState,
|
||||
initialEditorCamera,
|
||||
setEditorOpen,
|
||||
createSnapshot,
|
||||
] = useEditorStore(
|
||||
(state) => [
|
||||
state.sceneSnapshot,
|
||||
state.editorOpen,
|
||||
state.initialState,
|
||||
state.initialEditorCamera,
|
||||
state.setEditorOpen,
|
||||
state.createSnapshot,
|
||||
],
|
||||
shallow,
|
||||
)
|
||||
const [editorObject, sceneSnapshot, initialEditorCamera, createSnapshot] =
|
||||
useEditorStore(
|
||||
(state) => [
|
||||
state.editorObject,
|
||||
state.sceneSnapshot,
|
||||
state.initialEditorCamera,
|
||||
state.createSnapshot,
|
||||
],
|
||||
shallow,
|
||||
)
|
||||
|
||||
const editorOpen = !!useVal(editorObject?.props._isOpen)
|
||||
useLayoutEffect(() => {
|
||||
if (editorOpen) {
|
||||
createSnapshot()
|
||||
}
|
||||
}, [editorOpen])
|
||||
|
||||
if (!editorObject) return <></>
|
||||
|
||||
return (
|
||||
<root.div>
|
||||
|
@ -110,67 +113,15 @@ const Editor: VFC = () => {
|
|||
|
||||
<UI />
|
||||
</>
|
||||
) : (
|
||||
<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>
|
||||
)}
|
||||
) : null}
|
||||
</div>
|
||||
{editorOpen || (
|
||||
<Button
|
||||
className="fixed bottom-5 left-5"
|
||||
onClick={() => {
|
||||
if (!sceneSnapshot) {
|
||||
createSnapshot()
|
||||
}
|
||||
setEditorOpen(true)
|
||||
studio.transaction(({set}) => {
|
||||
set(editorObject.props._isOpen, 1)
|
||||
})
|
||||
}}
|
||||
>
|
||||
Editor
|
||||
|
|
|
@ -145,10 +145,11 @@ const ProxyManager: VFC<ProxyManagerProps> = ({orbitControlsRef}) => {
|
|||
setRenderMaterials(renderMaterials)
|
||||
|
||||
return () => {
|
||||
Object.entries(renderMaterials).forEach(([id, material]) => {
|
||||
;(sceneProxy.getObjectById(Number.parseInt(id)) as Mesh).material =
|
||||
material
|
||||
})
|
||||
// @todo do we need this cleanup?
|
||||
// Object.entries(renderMaterials).forEach(([id, material]) => {
|
||||
// ;(sceneProxy.getObjectById(Number.parseInt(id)) as Mesh).material =
|
||||
// material
|
||||
// })
|
||||
}
|
||||
}, [sceneProxy])
|
||||
|
||||
|
|
|
@ -11,9 +11,11 @@ import {Vector3} from 'three'
|
|||
import {IconButton, Button, SettingsButton} from './elements'
|
||||
import ViewportSettings from './ViewportSettings'
|
||||
import type {$FixMe} from '@theatre/shared/utils/types'
|
||||
import studio from '@theatre/studio'
|
||||
|
||||
const UI: VFC = () => {
|
||||
const [
|
||||
editorObject,
|
||||
transformControlsMode,
|
||||
transformControlsSpace,
|
||||
viewportShading,
|
||||
|
@ -21,9 +23,9 @@ const UI: VFC = () => {
|
|||
setTransformControlsMode,
|
||||
setTransformControlsSpace,
|
||||
setViewportShading,
|
||||
setEditorOpen,
|
||||
] = useEditorStore(
|
||||
(state) => [
|
||||
state.editorObject,
|
||||
state.transformControlsMode,
|
||||
state.transformControlsSpace,
|
||||
state.viewportShading,
|
||||
|
@ -31,11 +33,12 @@ const UI: VFC = () => {
|
|||
state.setTransformControlsMode,
|
||||
state.setTransformControlsSpace,
|
||||
state.setViewportShading,
|
||||
state.setEditorOpen,
|
||||
],
|
||||
shallow,
|
||||
)
|
||||
|
||||
if (!editorObject) return <></>
|
||||
|
||||
return (
|
||||
<div className="absolute inset-0 z-50 pointer-events-none">
|
||||
<div className="flex h-full">
|
||||
|
@ -134,7 +137,11 @@ const UI: VFC = () => {
|
|||
{/* Bottom-left corner*/}
|
||||
<Button
|
||||
className="absolute left-0 bottom-0 pointer-events-auto"
|
||||
onClick={() => setEditorOpen(false)}
|
||||
onClick={() =>
|
||||
studio.transaction(({set}) => {
|
||||
set(editorObject.props._isOpen, 0)
|
||||
})
|
||||
}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
|
|
|
@ -137,7 +137,7 @@ export interface EditableState {
|
|||
|
||||
export type EditorStore = {
|
||||
sheet: ISheet | null
|
||||
uiSheet: ISheet | null
|
||||
editorObject: ISheetObject<typeof editorSheetObjectConfig['props']> | null
|
||||
sheetObjects: {[uniqueName in string]?: BaseSheetObjectType}
|
||||
scene: Scene | null
|
||||
gl: WebGLRenderer | null
|
||||
|
@ -152,7 +152,6 @@ export type EditorStore = {
|
|||
transformControlsMode: TransformControlsMode
|
||||
transformControlsSpace: TransformControlsSpace
|
||||
viewportShading: ViewportShading
|
||||
editorOpen: boolean
|
||||
sceneSnapshot: Scene | null
|
||||
editablesSnapshot: Record<string, EditableSnapshot> | null
|
||||
hdrPaths: string[]
|
||||
|
@ -170,7 +169,7 @@ export type EditorStore = {
|
|||
allowImplicitInstancing: boolean,
|
||||
editorCamera: ContainerProps['camera'],
|
||||
sheet: ISheet,
|
||||
uiSheet: null | ISheet,
|
||||
editorObject: null | ISheetObject<typeof editorSheetObjectConfig['props']>,
|
||||
) => void
|
||||
|
||||
setOrbitControlsRef: (
|
||||
|
@ -187,7 +186,6 @@ export type EditorStore = {
|
|||
setShowGrid: (show: boolean) => void
|
||||
setShowAxes: (show: boolean) => void
|
||||
setReferenceWindowSize: (size: number) => void
|
||||
setEditorOpen: (open: boolean) => void
|
||||
createSnapshot: () => void
|
||||
setSheetObject: (uniqueName: string, sheetObject: BaseSheetObjectType) => void
|
||||
setSnapshotProxyObject: (
|
||||
|
@ -214,7 +212,7 @@ const config: StateCreator<EditorStore> = (set, get) => {
|
|||
|
||||
return {
|
||||
sheet: null,
|
||||
uiSheet: null,
|
||||
editorObject: null,
|
||||
sheetObjects: {},
|
||||
scene: null,
|
||||
gl: null,
|
||||
|
@ -228,7 +226,6 @@ const config: StateCreator<EditorStore> = (set, get) => {
|
|||
transformControlsMode: 'translate',
|
||||
transformControlsSpace: 'world',
|
||||
viewportShading: 'rendered',
|
||||
editorOpen: false,
|
||||
sceneSnapshot: null,
|
||||
editablesSnapshot: null,
|
||||
hdrPaths: [],
|
||||
|
@ -246,7 +243,7 @@ const config: StateCreator<EditorStore> = (set, get) => {
|
|||
allowImplicitInstancing,
|
||||
editorCamera,
|
||||
sheet,
|
||||
uiSheet,
|
||||
editorObject,
|
||||
) => {
|
||||
set({
|
||||
scene,
|
||||
|
@ -254,7 +251,7 @@ const config: StateCreator<EditorStore> = (set, get) => {
|
|||
allowImplicitInstancing,
|
||||
initialEditorCamera: editorCamera,
|
||||
sheet,
|
||||
uiSheet,
|
||||
editorObject,
|
||||
})
|
||||
},
|
||||
|
||||
|
@ -339,9 +336,6 @@ const config: StateCreator<EditorStore> = (set, get) => {
|
|||
set({showAxes: show})
|
||||
},
|
||||
setReferenceWindowSize: (size) => set({referenceWindowSize: size}),
|
||||
setEditorOpen: (open) => {
|
||||
set({editorOpen: open})
|
||||
},
|
||||
createSnapshot: () => {
|
||||
set((state) => ({
|
||||
sceneSnapshot: state.scene?.clone() ?? null,
|
||||
|
@ -370,6 +364,12 @@ export type BindFunction = (options: {
|
|||
sheet: ISheet
|
||||
}) => (options: {gl: WebGLRenderer; scene: Scene}) => void
|
||||
|
||||
const editorSheetObjectConfig = {
|
||||
props: types.compound({
|
||||
_isOpen: types.number(0),
|
||||
}),
|
||||
}
|
||||
|
||||
export const bindToCanvas: BindFunction = ({
|
||||
allowImplicitInstancing = false,
|
||||
editorCamera = {},
|
||||
|
@ -380,6 +380,9 @@ export const bindToCanvas: BindFunction = ({
|
|||
? getProject('R3F Plugin').sheet('UI')
|
||||
: null
|
||||
|
||||
const editorSheetObject =
|
||||
uiSheet?.object('Editor', null, editorSheetObjectConfig) || null
|
||||
|
||||
return ({gl, scene}) => {
|
||||
const init = useEditorStore.getState().init
|
||||
init(
|
||||
|
@ -388,7 +391,7 @@ export const bindToCanvas: BindFunction = ({
|
|||
allowImplicitInstancing,
|
||||
{...{position: [20, 20, 20]}, ...editorCamera},
|
||||
sheet,
|
||||
uiSheet,
|
||||
editorSheetObject,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue