Support multiple sheet instances (#153)
* Support multiple/nested sheets and sheet instances * Add playground for instances * Fix playground and example * Change r3f's objectKey to storeKey to avoid confusion * Update all editable/uniqueName variables used as store key to storeKey too * Fix lint warnings
This commit is contained in:
parent
10b4954ee2
commit
fc9df7c346
11 changed files with 195 additions and 88 deletions
|
@ -92,7 +92,7 @@ function App() {
|
||||||
shadowMap
|
shadowMap
|
||||||
>
|
>
|
||||||
<SheetProvider
|
<SheetProvider
|
||||||
getSheet={() => getProject('Playground - R3F').sheet('R3F-Canvas')}
|
sheet={getProject('Playground - R3F').sheet('R3F-Canvas')}
|
||||||
>
|
>
|
||||||
{/* @ts-ignore */}
|
{/* @ts-ignore */}
|
||||||
<e.perspectiveCamera makeDefault uniqueName="Camera" />
|
<e.perspectiveCamera makeDefault uniqueName="Camera" />
|
||||||
|
|
109
packages/playground/src/shared/instances/App.tsx
Normal file
109
packages/playground/src/shared/instances/App.tsx
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
import {editable as e, RefreshSnapshot, SheetProvider} from '@theatre/r3f'
|
||||||
|
import {Stars} from '@react-three/drei'
|
||||||
|
import {getProject} from '@theatre/core'
|
||||||
|
import React, {Suspense, useState} from 'react'
|
||||||
|
import {Canvas} from '@react-three/fiber'
|
||||||
|
import {useGLTF, PerspectiveCamera} from '@react-three/drei'
|
||||||
|
import sceneGLB from './scene.glb'
|
||||||
|
|
||||||
|
document.body.style.backgroundColor = '#171717'
|
||||||
|
|
||||||
|
const EditableCamera = e(PerspectiveCamera, 'perspectiveCamera')
|
||||||
|
|
||||||
|
function Model({
|
||||||
|
url,
|
||||||
|
instance,
|
||||||
|
...props
|
||||||
|
}: {url: string; instance?: string} & JSX.IntrinsicElements['group']) {
|
||||||
|
const {nodes} = useGLTF(url) as any
|
||||||
|
|
||||||
|
return (
|
||||||
|
<e.group
|
||||||
|
uniqueName={`Transforms for Rocket: ${instance ?? 'default'}`}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<SheetProvider sheet={getProject('Space').sheet('Rocket', instance)}>
|
||||||
|
<group rotation={[-Math.PI / 2, 0, 0]} position={[0, -7, 0]} scale={7}>
|
||||||
|
<group rotation={[Math.PI / 13.5, -Math.PI / 5.8, Math.PI / 5.6]}>
|
||||||
|
<e.mesh
|
||||||
|
uniqueName="Thingy"
|
||||||
|
receiveShadow
|
||||||
|
castShadow
|
||||||
|
geometry={nodes.planet001.geometry}
|
||||||
|
material={nodes.planet001.material}
|
||||||
|
/>
|
||||||
|
<e.mesh
|
||||||
|
uniqueName="Debris 2"
|
||||||
|
receiveShadow
|
||||||
|
castShadow
|
||||||
|
geometry={nodes.planet002.geometry}
|
||||||
|
material={nodes.planet002.material}
|
||||||
|
/>
|
||||||
|
<e.mesh
|
||||||
|
uniqueName="Debris 1"
|
||||||
|
geometry={nodes.planet003.geometry}
|
||||||
|
material={nodes.planet003.material}
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</SheetProvider>
|
||||||
|
</e.group>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const bgs = ['#272730', '#b7c5d1']
|
||||||
|
const [bgIndex, setBgIndex] = useState(0)
|
||||||
|
const bg = bgs[bgIndex]
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
// return setBgIndex((bgIndex) => (bgIndex + 1) % bgs.length)
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
height: '100vh',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Canvas dpr={[1.5, 2]} linear shadows frameloop="demand">
|
||||||
|
<SheetProvider sheet={getProject('Space').sheet('Scene')}>
|
||||||
|
<fog attach="fog" args={[bg, 16, 70]} />
|
||||||
|
<color attach="background" args={[bg]} />
|
||||||
|
<ambientLight intensity={0.75} />
|
||||||
|
<EditableCamera
|
||||||
|
uniqueName="Camera"
|
||||||
|
makeDefault
|
||||||
|
position={[0, 0, 0]}
|
||||||
|
fov={75}
|
||||||
|
near={20}
|
||||||
|
far={70}
|
||||||
|
>
|
||||||
|
<e.pointLight
|
||||||
|
uniqueName="Light 1"
|
||||||
|
intensity={1}
|
||||||
|
position={[-10, -25, -10]}
|
||||||
|
/>
|
||||||
|
<e.spotLight
|
||||||
|
uniqueName="Light 2"
|
||||||
|
castShadow
|
||||||
|
intensity={2.25}
|
||||||
|
angle={0.2}
|
||||||
|
penumbra={1}
|
||||||
|
position={[-25, 20, -15]}
|
||||||
|
shadow-mapSize={[1024, 1024]}
|
||||||
|
shadow-bias={-0.0001}
|
||||||
|
/>
|
||||||
|
<e.directionalLight uniqueName="Light 3" />
|
||||||
|
</EditableCamera>
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<RefreshSnapshot />
|
||||||
|
<Model url={sceneGLB} instance="Apollo" position={[18, 5, -42]} />
|
||||||
|
<Model url={sceneGLB} instance="Sputnik" position={[-18, 5, -42]} />
|
||||||
|
</Suspense>
|
||||||
|
<Stars radius={500} depth={50} count={1000} factor={10} />
|
||||||
|
</SheetProvider>
|
||||||
|
</Canvas>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App
|
15
packages/playground/src/shared/instances/index.tsx
Normal file
15
packages/playground/src/shared/instances/index.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import App from './App'
|
||||||
|
import studio from '@theatre/studio'
|
||||||
|
import {extension} from '@theatre/r3f'
|
||||||
|
|
||||||
|
studio.extend(extension)
|
||||||
|
studio.initialize()
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>,
|
||||||
|
document.getElementById('root'),
|
||||||
|
)
|
BIN
packages/playground/src/shared/instances/scene.glb
Normal file
BIN
packages/playground/src/shared/instances/scene.glb
Normal file
Binary file not shown.
|
@ -1,11 +1,10 @@
|
||||||
import {editable as e, RefreshSnapshot, SheetProvider} from '@theatre/r3f'
|
import {editable as e, RefreshSnapshot, SheetProvider} from '@theatre/r3f'
|
||||||
import {Stars} from '@react-three/drei'
|
import {Stars} from '@react-three/drei'
|
||||||
import {getProject} from '@theatre/core'
|
import {getProject} from '@theatre/core'
|
||||||
import React, {Suspense, useMemo, useState} from 'react'
|
import React, {Suspense, useState} from 'react'
|
||||||
import {Canvas} from '@react-three/fiber'
|
import {Canvas} from '@react-three/fiber'
|
||||||
import {useGLTF, PerspectiveCamera} from '@react-three/drei'
|
import {useGLTF, PerspectiveCamera} from '@react-three/drei'
|
||||||
import sceneGLB from './scene.glb'
|
import sceneGLB from './scene.glb'
|
||||||
import {Color} from 'three'
|
|
||||||
|
|
||||||
document.body.style.backgroundColor = '#171717'
|
document.body.style.backgroundColor = '#171717'
|
||||||
|
|
||||||
|
@ -55,14 +54,8 @@ function App() {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Canvas dpr={[1.5, 2]} linear shadows frameloop="demand">
|
<Canvas dpr={[1.5, 2]} linear shadows frameloop="demand">
|
||||||
<SheetProvider getSheet={() => getProject('Space').sheet('Scene')}>
|
<SheetProvider sheet={getProject('Space').sheet('Scene')}>
|
||||||
<e.fog
|
<fog attach="fog" args={[bg, 16, 30]} />
|
||||||
attach="fog"
|
|
||||||
color={useMemo(() => new Color(bg), [bg])}
|
|
||||||
near={16}
|
|
||||||
far={30}
|
|
||||||
uniqueName="Fog"
|
|
||||||
/>
|
|
||||||
<color attach="background" args={[bg]} />
|
<color attach="background" args={[bg]} />
|
||||||
<ambientLight intensity={0.75} />
|
<ambientLight intensity={0.75} />
|
||||||
<EditableCamera
|
<EditableCamera
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import React, {
|
import React, {
|
||||||
createContext,
|
createContext,
|
||||||
useContext,
|
useContext,
|
||||||
|
useEffect,
|
||||||
useLayoutEffect,
|
useLayoutEffect,
|
||||||
useState,
|
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import {useThree} from '@react-three/fiber'
|
import {useThree} from '@react-three/fiber'
|
||||||
import type {ISheet} from '@theatre/core'
|
import type {ISheet} from '@theatre/core'
|
||||||
import {bindToCanvas} from './store'
|
import {bindToCanvas} from './store'
|
||||||
|
|
||||||
const ctx = createContext<{sheet: ISheet | undefined} | undefined>(undefined)
|
const ctx = createContext<{sheet: ISheet}>(undefined!)
|
||||||
|
|
||||||
const useWrapperContext = (): {sheet: ISheet | undefined} => {
|
const useWrapperContext = (): {sheet: ISheet} => {
|
||||||
const val = useContext(ctx)
|
const val = useContext(ctx)
|
||||||
if (!val) {
|
if (!val) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -25,23 +25,21 @@ export const useCurrentSheet = (): ISheet | undefined => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const SheetProvider: React.FC<{
|
const SheetProvider: React.FC<{
|
||||||
getSheet: () => ISheet
|
sheet: ISheet
|
||||||
}> = (props) => {
|
}> = ({sheet, children}) => {
|
||||||
const {scene, gl} = useThree((s) => ({scene: s.scene, gl: s.gl}))
|
const {scene, gl} = useThree((s) => ({scene: s.scene, gl: s.gl}))
|
||||||
const [sheet, setSheet] = useState<ISheet | undefined>(undefined)
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!sheet || sheet.type !== 'Theatre_Sheet_PublicAPI') {
|
||||||
|
throw new Error(`sheet in <Wrapper sheet={sheet}> has an invalid value`)
|
||||||
|
}
|
||||||
|
}, [sheet])
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const sheet = props.getSheet()
|
|
||||||
if (!sheet || sheet.type !== 'Theatre_Sheet_PublicAPI') {
|
|
||||||
throw new Error(
|
|
||||||
`getSheet() in <Wrapper getSheet={getSheet}> has returned an invalid value`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
setSheet(sheet)
|
|
||||||
bindToCanvas({gl, scene})
|
bindToCanvas({gl, scene})
|
||||||
}, [scene, gl])
|
}, [scene, gl])
|
||||||
|
|
||||||
return <ctx.Provider value={{sheet}}>{props.children}</ctx.Provider>
|
return <ctx.Provider value={{sheet}}>{children}</ctx.Provider>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SheetProvider
|
export default SheetProvider
|
||||||
|
|
|
@ -15,14 +15,11 @@ import {invalidate, useFrame, useThree} from '@react-three/fiber'
|
||||||
import {useDragDetector} from './DragDetector'
|
import {useDragDetector} from './DragDetector'
|
||||||
|
|
||||||
export interface EditableProxyProps {
|
export interface EditableProxyProps {
|
||||||
editableName: string
|
storeKey: string
|
||||||
object: Object3D
|
object: Object3D
|
||||||
}
|
}
|
||||||
|
|
||||||
const EditableProxy: VFC<EditableProxyProps> = ({
|
const EditableProxy: VFC<EditableProxyProps> = ({storeKey, object}) => {
|
||||||
editableName: uniqueName,
|
|
||||||
object,
|
|
||||||
}) => {
|
|
||||||
const editorObject = getEditorSheetObject()
|
const editorObject = getEditorSheetObject()
|
||||||
const [setSnapshotProxyObject, editables] = useEditorStore(
|
const [setSnapshotProxyObject, editables] = useEditorStore(
|
||||||
(state) => [state.setSnapshotProxyObject, state.editables],
|
(state) => [state.setSnapshotProxyObject, state.editables],
|
||||||
|
@ -31,17 +28,17 @@ const EditableProxy: VFC<EditableProxyProps> = ({
|
||||||
|
|
||||||
const dragging = useDragDetector()
|
const dragging = useDragDetector()
|
||||||
|
|
||||||
const editable = editables[uniqueName]
|
const editable = editables[storeKey]
|
||||||
|
|
||||||
const selected = useSelected()
|
const selected = useSelected()
|
||||||
const showOverlayIcons =
|
const showOverlayIcons =
|
||||||
useVal(editorObject?.props.viewport.showOverlayIcons) ?? false
|
useVal(editorObject?.props.viewport.showOverlayIcons) ?? false
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSnapshotProxyObject(object, uniqueName)
|
setSnapshotProxyObject(object, storeKey)
|
||||||
|
|
||||||
return () => setSnapshotProxyObject(null, uniqueName)
|
return () => setSnapshotProxyObject(null, storeKey)
|
||||||
}, [uniqueName, object, setSnapshotProxyObject])
|
}, [storeKey, object, setSnapshotProxyObject])
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const originalVisibility = object.visible
|
const originalVisibility = object.visible
|
||||||
|
@ -68,7 +65,7 @@ const EditableProxy: VFC<EditableProxyProps> = ({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected === uniqueName || hovered) {
|
if (selected === storeKey || hovered) {
|
||||||
scene.add(helper)
|
scene.add(helper)
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
|
@ -93,6 +90,30 @@ const EditableProxy: VFC<EditableProxyProps> = ({
|
||||||
}
|
}
|
||||||
}, [dragging])
|
}, [dragging])
|
||||||
|
|
||||||
|
// subscribe to external changes
|
||||||
|
useEffect(() => {
|
||||||
|
const sheetObject = editable.sheetObject
|
||||||
|
const objectConfig = editable.objectConfig
|
||||||
|
|
||||||
|
const setFromTheatre = (newValues: any) => {
|
||||||
|
// @ts-ignore
|
||||||
|
Object.entries(objectConfig.props).forEach(([key, value]) => {
|
||||||
|
// @ts-ignore
|
||||||
|
return value.apply(newValues[key], object)
|
||||||
|
})
|
||||||
|
objectConfig.updateObject?.(object)
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
setFromTheatre(sheetObject.value)
|
||||||
|
|
||||||
|
const untap = sheetObject.onValuesChange(setFromTheatre)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
untap()
|
||||||
|
}
|
||||||
|
}, [editable])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<group
|
<group
|
||||||
|
@ -101,10 +122,10 @@ const EditableProxy: VFC<EditableProxyProps> = ({
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
||||||
const theatreObject =
|
const theatreObject =
|
||||||
useEditorStore.getState().editables[uniqueName].sheetObject
|
useEditorStore.getState().editables[storeKey].sheetObject
|
||||||
|
|
||||||
if (!theatreObject) {
|
if (!theatreObject) {
|
||||||
console.log('no theatre object for', uniqueName)
|
console.log('no theatre object for', storeKey)
|
||||||
} else {
|
} else {
|
||||||
studio.setSelection([theatreObject])
|
studio.setSelection([theatreObject])
|
||||||
}
|
}
|
||||||
|
@ -129,8 +150,7 @@ const EditableProxy: VFC<EditableProxyProps> = ({
|
||||||
>
|
>
|
||||||
<primitive object={object}>
|
<primitive object={object}>
|
||||||
{(showOverlayIcons ||
|
{(showOverlayIcons ||
|
||||||
(editable.objectConfig.dimensionless &&
|
(editable.objectConfig.dimensionless && selected !== storeKey)) && (
|
||||||
selected !== uniqueName)) && (
|
|
||||||
<Html
|
<Html
|
||||||
center
|
center
|
||||||
style={{
|
style={{
|
||||||
|
@ -149,10 +169,10 @@ const EditableProxy: VFC<EditableProxyProps> = ({
|
||||||
if (e.delta < 2) {
|
if (e.delta < 2) {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
const theatreObject =
|
const theatreObject =
|
||||||
useEditorStore.getState().editables[uniqueName].sheetObject
|
useEditorStore.getState().editables[storeKey].sheetObject
|
||||||
|
|
||||||
if (!theatreObject) {
|
if (!theatreObject) {
|
||||||
console.log('no theatre object for', uniqueName)
|
console.log('no theatre object for', storeKey)
|
||||||
} else {
|
} else {
|
||||||
studio.setSelection([theatreObject])
|
studio.setSelection([theatreObject])
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
import type {VFC} from 'react'
|
import type {VFC} from 'react'
|
||||||
import React, {
|
import React, {useLayoutEffect, useMemo, useRef, useState} from 'react'
|
||||||
useEffect,
|
|
||||||
useLayoutEffect,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react'
|
|
||||||
import type {Editable} from '../store'
|
import type {Editable} from '../store'
|
||||||
import {useEditorStore} from '../store'
|
import {useEditorStore} from '../store'
|
||||||
import {createPortal} from '@react-three/fiber'
|
import {createPortal} from '@react-three/fiber'
|
||||||
|
@ -15,11 +9,10 @@ import TransformControls from './TransformControls'
|
||||||
import shallow from 'zustand/shallow'
|
import shallow from 'zustand/shallow'
|
||||||
import type {Material, Mesh, Object3D} from 'three'
|
import type {Material, Mesh, Object3D} from 'three'
|
||||||
import {MeshBasicMaterial, MeshPhongMaterial} from 'three'
|
import {MeshBasicMaterial, MeshPhongMaterial} from 'three'
|
||||||
import type {IScrub} from '@theatre/studio';
|
import type {IScrub} from '@theatre/studio'
|
||||||
import studio from '@theatre/studio'
|
import studio from '@theatre/studio'
|
||||||
import {useSelected} from './useSelected'
|
import {useSelected} from './useSelected'
|
||||||
import {useVal} from '@theatre/react'
|
import {useVal} from '@theatre/react'
|
||||||
import useInvalidate from './useInvalidate'
|
|
||||||
import {getEditorSheetObject} from './editorStuff'
|
import {getEditorSheetObject} from './editorStuff'
|
||||||
|
|
||||||
export interface ProxyManagerProps {
|
export interface ProxyManagerProps {
|
||||||
|
@ -55,8 +48,6 @@ const ProxyManager: VFC<ProxyManagerProps> = ({orbitControlsRef}) => {
|
||||||
}
|
}
|
||||||
>({})
|
>({})
|
||||||
|
|
||||||
const invalidate = useInvalidate()
|
|
||||||
|
|
||||||
// set up scene proxies
|
// set up scene proxies
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (!sceneProxy) {
|
if (!sceneProxy) {
|
||||||
|
@ -68,15 +59,15 @@ const ProxyManager: VFC<ProxyManagerProps> = ({orbitControlsRef}) => {
|
||||||
sceneProxy.traverse((object) => {
|
sceneProxy.traverse((object) => {
|
||||||
if (object.userData.__editable) {
|
if (object.userData.__editable) {
|
||||||
// there are duplicate uniqueNames in the scene, only display one instance in the editor
|
// there are duplicate uniqueNames in the scene, only display one instance in the editor
|
||||||
if (editableProxies[object.userData.__editableName]) {
|
if (editableProxies[object.userData.__storeKey]) {
|
||||||
object.parent!.remove(object)
|
object.parent!.remove(object)
|
||||||
} else {
|
} else {
|
||||||
const uniqueName = object.userData.__editableName
|
const uniqueName = object.userData.__storeKey
|
||||||
|
|
||||||
editableProxies[uniqueName] = {
|
editableProxies[uniqueName] = {
|
||||||
portal: createPortal(
|
portal: createPortal(
|
||||||
<EditableProxy
|
<EditableProxy
|
||||||
editableName={object.userData.__editableName}
|
storeKey={object.userData.__storeKey}
|
||||||
object={object}
|
object={object}
|
||||||
/>,
|
/>,
|
||||||
object.parent!,
|
object.parent!,
|
||||||
|
@ -95,32 +86,6 @@ const ProxyManager: VFC<ProxyManagerProps> = ({orbitControlsRef}) => {
|
||||||
const editableProxyOfSelected = selected && editableProxies[selected]
|
const editableProxyOfSelected = selected && editableProxies[selected]
|
||||||
const editable = selected ? editables[selected] : undefined
|
const editable = selected ? editables[selected] : undefined
|
||||||
|
|
||||||
// subscribe to external changes
|
|
||||||
useEffect(() => {
|
|
||||||
if (!editableProxyOfSelected || !editable) return
|
|
||||||
const object = editableProxyOfSelected.object
|
|
||||||
const sheetObject = editableProxyOfSelected.editable.sheetObject
|
|
||||||
const objectConfig = editable.objectConfig
|
|
||||||
|
|
||||||
const setFromTheatre = (newValues: any) => {
|
|
||||||
// @ts-ignore
|
|
||||||
Object.entries(objectConfig.props).forEach(([key, value]) => {
|
|
||||||
// @ts-ignore
|
|
||||||
return value.apply(newValues[key], object)
|
|
||||||
})
|
|
||||||
objectConfig.updateObject?.(object)
|
|
||||||
invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
setFromTheatre(sheetObject.value)
|
|
||||||
|
|
||||||
const untap = sheetObject.onValuesChange(setFromTheatre)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
untap()
|
|
||||||
}
|
|
||||||
}, [editableProxyOfSelected, selected])
|
|
||||||
|
|
||||||
// set up viewport shading modes
|
// set up viewport shading modes
|
||||||
const [renderMaterials, setRenderMaterials] = useState<{
|
const [renderMaterials, setRenderMaterials] = useState<{
|
||||||
[id: string]: Material | Material[]
|
[id: string]: Material | Material[]
|
||||||
|
|
|
@ -8,6 +8,7 @@ import useInvalidate from './useInvalidate'
|
||||||
import {useCurrentSheet} from '../SheetProvider'
|
import {useCurrentSheet} from '../SheetProvider'
|
||||||
import defaultEditableFactoryConfig from '../defaultEditableFactoryConfig'
|
import defaultEditableFactoryConfig from '../defaultEditableFactoryConfig'
|
||||||
import type {EditableFactoryConfig} from '../editableFactoryConfigUtils'
|
import type {EditableFactoryConfig} from '../editableFactoryConfigUtils'
|
||||||
|
import {makeStoreKey} from '../utils'
|
||||||
|
|
||||||
const createEditable = <Keys extends keyof JSX.IntrinsicElements>(
|
const createEditable = <Keys extends keyof JSX.IntrinsicElements>(
|
||||||
config: EditableFactoryConfig,
|
config: EditableFactoryConfig,
|
||||||
|
@ -47,7 +48,9 @@ const createEditable = <Keys extends keyof JSX.IntrinsicElements>(
|
||||||
|
|
||||||
const objectRef = useRef<JSX.IntrinsicElements[U]>()
|
const objectRef = useRef<JSX.IntrinsicElements[U]>()
|
||||||
|
|
||||||
const sheet = useCurrentSheet()
|
const sheet = useCurrentSheet()!
|
||||||
|
|
||||||
|
const storeKey = makeStoreKey(sheet, uniqueName)
|
||||||
|
|
||||||
const [sheetObject, setSheetObject] = useState<
|
const [sheetObject, setSheetObject] = useState<
|
||||||
undefined | ISheetObject<$FixMe>
|
undefined | ISheetObject<$FixMe>
|
||||||
|
@ -75,14 +78,14 @@ const createEditable = <Keys extends keyof JSX.IntrinsicElements>(
|
||||||
|
|
||||||
if (objRef) objRef!.current = sheetObject
|
if (objRef) objRef!.current = sheetObject
|
||||||
|
|
||||||
useEditorStore.getState().addEditable(uniqueName, {
|
useEditorStore.getState().addEditable(storeKey, {
|
||||||
type: actualType,
|
type: actualType,
|
||||||
sheetObject,
|
sheetObject,
|
||||||
visibleOnlyInEditor: visible === 'editor',
|
visibleOnlyInEditor: visible === 'editor',
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
objectConfig: config[actualType],
|
objectConfig: config[actualType],
|
||||||
})
|
})
|
||||||
}, [sheet, uniqueName])
|
}, [sheet, storeKey])
|
||||||
|
|
||||||
// store initial values of props
|
// store initial values of props
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
|
@ -95,7 +98,6 @@ const createEditable = <Keys extends keyof JSX.IntrinsicElements>(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}, [
|
}, [
|
||||||
uniqueName,
|
|
||||||
sheetObject,
|
sheetObject,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
...Object.keys(config[actualType].props).map(
|
...Object.keys(config[actualType].props).map(
|
||||||
|
@ -138,7 +140,7 @@ const createEditable = <Keys extends keyof JSX.IntrinsicElements>(
|
||||||
visible={visible !== 'editor' && visible}
|
visible={visible !== 'editor' && visible}
|
||||||
userData={{
|
userData={{
|
||||||
__editable: true,
|
__editable: true,
|
||||||
__editableName: uniqueName,
|
__storeKey: storeKey,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {allRegisteredObjects} from '../store'
|
||||||
import studio from '@theatre/studio'
|
import studio from '@theatre/studio'
|
||||||
import type {ISheetObject} from '@theatre/core'
|
import type {ISheetObject} from '@theatre/core'
|
||||||
import type {$IntentionalAny} from '../types'
|
import type {$IntentionalAny} from '../types'
|
||||||
|
import {makeStoreKey} from '../utils'
|
||||||
|
|
||||||
export function useSelected(): undefined | string {
|
export function useSelected(): undefined | string {
|
||||||
const [state, set] = useState<string | undefined>(undefined)
|
const [state, set] = useState<string | undefined>(undefined)
|
||||||
|
@ -19,7 +20,7 @@ export function useSelected(): undefined | string {
|
||||||
if (!item) {
|
if (!item) {
|
||||||
set(undefined)
|
set(undefined)
|
||||||
} else {
|
} else {
|
||||||
set(item.address.objectKey)
|
set(makeStoreKey(item.sheet, item.address.objectKey))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setFromStudio(studio.selection)
|
setFromStudio(studio.selection)
|
||||||
|
@ -38,6 +39,6 @@ export function getSelected(): undefined | string {
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return undefined
|
return undefined
|
||||||
} else {
|
} else {
|
||||||
return item.address.objectKey
|
return makeStoreKey(item.sheet, item.address.objectKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
import {useEditorStore} from './store'
|
import {useEditorStore} from './store'
|
||||||
|
import type {ISheet} from '@theatre/core'
|
||||||
|
|
||||||
export const refreshSnapshot = useEditorStore.getState().createSnapshot
|
export const refreshSnapshot = useEditorStore.getState().createSnapshot
|
||||||
|
|
||||||
|
export const makeStoreKey = (sheet: ISheet, name: string) =>
|
||||||
|
`${sheet.address.sheetId}:${sheet.address.sheetInstanceId}:${name}`
|
||||||
|
|
Loading…
Reference in a new issue