New: Store the editorOpen state in Theatre

This commit is contained in:
Aria Minaei 2021-07-02 20:43:25 +02:00
parent 08759e2d5c
commit 6ac6aa87d7
4 changed files with 56 additions and 94 deletions

View file

@ -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

View file

@ -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])

View file

@ -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>

View file

@ -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,
)
}
}