Extensions can now use studio's project for editing-related objects.

This commit is contained in:
Aria Minaei 2021-08-08 21:33:10 +02:00
parent 828fbb97b5
commit b08588e9d6
4 changed files with 91 additions and 104 deletions

View file

@ -9,8 +9,7 @@ import studio, {ToolbarIconButton} from '@theatre/studio'
import {useVal} from '@theatre/dataverse-react' import {useVal} from '@theatre/dataverse-react'
import styled, {createGlobalStyle, StyleSheetManager} from 'styled-components' import styled, {createGlobalStyle, StyleSheetManager} from 'styled-components'
import {IoCameraReverseOutline} from 'react-icons/all' import {IoCameraReverseOutline} from 'react-icons/all'
import type {ISheetObject, ISheet} from '@theatre/core' import type {ISheet} from '@theatre/core'
import type {$FixMe} from '../types'
import useSnapshotEditorCamera from './useSnapshotEditorCamera' import useSnapshotEditorCamera from './useSnapshotEditorCamera'
const GlobalStyle = createGlobalStyle` const GlobalStyle = createGlobalStyle`
@ -95,87 +94,86 @@ const Tools = styled.div`
pointer-events: auto; pointer-events: auto;
` `
const SnapshotEditor: React.FC<{object: ISheetObject<$FixMe>; paneId: string}> = const SnapshotEditor: React.FC<{paneId: string}> = (props) => {
(props) => { const snapshotEditorSheet = studio.getStudioProject().sheet('Plugin-R3F')
const snapshotEditorSheet = props.object.sheet const paneId = props.paneId
const paneId = props.paneId
const [editorObject, sceneSnapshot, createSnapshot, sheet] = useEditorStore( const [editorObject, sceneSnapshot, createSnapshot, sheet] = useEditorStore(
(state) => [ (state) => [
state.editorObject, state.editorObject,
state.sceneSnapshot, state.sceneSnapshot,
state.createSnapshot, state.createSnapshot,
state.sheet, state.sheet,
], ],
shallow, shallow,
) )
const editorOpen = true const editorOpen = true
useLayoutEffect(() => { useLayoutEffect(() => {
let timeout: NodeJS.Timeout | undefined let timeout: NodeJS.Timeout | undefined
if (editorOpen) { if (editorOpen) {
// a hack to make sure all the scene's props are // a hack to make sure all the scene's props are
// applied before we take a snapshot // applied before we take a snapshot
timeout = setTimeout(createSnapshot, 100) timeout = setTimeout(createSnapshot, 100)
}
return () => {
if (timeout !== undefined) {
clearTimeout(timeout)
} }
return () => { }
if (timeout !== undefined) { }, [editorOpen])
clearTimeout(timeout)
}
}
}, [editorOpen])
const onPointerMissed = useCallback(() => { const onPointerMissed = useCallback(() => {
if (sheet !== null) studio.__experimental_setSelection([sheet]) if (sheet !== null) studio.__experimental_setSelection([sheet])
}, [sheet]) }, [sheet])
if (!editorObject) return <></> if (!editorObject) return <></>
return ( return (
<root.div> <root.div>
<StyleSheetManager disableVendorPrefixes> <StyleSheetManager disableVendorPrefixes>
<> <>
<GlobalStyle /> <GlobalStyle />
<Wrapper> <Wrapper>
<Overlay> <Overlay>
<Tools> <Tools>
<ToolbarIconButton <ToolbarIconButton
icon={<IoCameraReverseOutline />} icon={<IoCameraReverseOutline />}
label="Refresh Snapshot" label="Refresh Snapshot"
onClick={createSnapshot} onClick={createSnapshot}
></ToolbarIconButton> ></ToolbarIconButton>
</Tools> </Tools>
</Overlay> </Overlay>
{sceneSnapshot ? ( {sceneSnapshot ? (
<> <>
<CanvasWrapper> <CanvasWrapper>
<Canvas <Canvas
// @ts-ignore // @ts-ignore
colorManagement colorManagement
onCreated={({gl}) => { onCreated={({gl}) => {
gl.setClearColor('white') gl.setClearColor('white')
}} }}
shadowMap shadowMap
dpr={[1, 2]} dpr={[1, 2]}
fog={'red'} fog={'red'}
frameloop="demand" frameloop="demand"
onPointerMissed={onPointerMissed} onPointerMissed={onPointerMissed}
> >
<EditorScene <EditorScene
snapshotEditorSheet={snapshotEditorSheet} snapshotEditorSheet={snapshotEditorSheet}
paneId={paneId} paneId={paneId}
/> />
</Canvas> </Canvas>
</CanvasWrapper> </CanvasWrapper>
</> </>
) : null} ) : null}
</Wrapper> </Wrapper>
{/* </PortalContext.Provider> */} {/* </PortalContext.Provider> */}
</> </>
</StyleSheetManager> </StyleSheetManager>
</root.div> </root.div>
) )
} }
export default SnapshotEditor export default SnapshotEditor

View file

@ -1,7 +1,7 @@
import {prism, val} from '@theatre/dataverse' import {prism, val} from '@theatre/dataverse'
import {emptyArray} from '@theatre/shared/utils' import {emptyArray} from '@theatre/shared/utils'
import SimpleCache from '@theatre/shared/utils/SimpleCache' import SimpleCache from '@theatre/shared/utils/SimpleCache'
import type {$FixMe, $IntentionalAny} from '@theatre/shared/utils/types' import type {$IntentionalAny} from '@theatre/shared/utils/types'
import type {Studio} from './Studio' import type {Studio} from './Studio'
import type {PaneInstance} from './TheatreStudio' import type {PaneInstance} from './TheatreStudio'
@ -43,20 +43,9 @@ export default class PaneManager {
const instance = prism.memo( const instance = prism.memo(
`instance-${instanceDescriptor!.instanceId}`, `instance-${instanceDescriptor!.instanceId}`,
() => { () => {
const object = this._studio
.getExtensionSheet(extensionId, core)
.object(
'Pane: ' + instanceId,
null,
core.types.compound({
panelThingy: core.types.boolean(false),
}),
) as $FixMe
const inst: PaneInstance<$IntentionalAny> = { const inst: PaneInstance<$IntentionalAny> = {
extensionId, extensionId,
instanceId, instanceId,
object,
definition, definition,
} }
return inst return inst

View file

@ -1,4 +1,4 @@
import type {ISheet, ISheetObject} from '@theatre/core' import type {IProject, ISheet, ISheetObject} from '@theatre/core'
import studioTicker from '@theatre/studio/studioTicker' import studioTicker from '@theatre/studio/studioTicker'
import type {IDerivation, Pointer} from '@theatre/dataverse' import type {IDerivation, Pointer} from '@theatre/dataverse'
import {prism} from '@theatre/dataverse' import {prism} from '@theatre/dataverse'
@ -15,10 +15,7 @@ import {getOutlineSelection} from './selectors'
import type SheetObject from '@theatre/core/sheetObjects/SheetObject' import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
import getStudio from './getStudio' import getStudio from './getStudio'
import type React from 'react' import type React from 'react'
import type { import type {PropTypeConfig_Compound} from '@theatre/core/propTypes'
PropTypeConfig_Boolean,
PropTypeConfig_Compound,
} from '@theatre/core/propTypes'
import {debounce} from 'lodash-es' import {debounce} from 'lodash-es'
export interface ITransactionAPI { export interface ITransactionAPI {
@ -33,12 +30,6 @@ export interface PaneClassDefinition<
dataType: DataType dataType: DataType
component: React.ComponentType<{ component: React.ComponentType<{
paneId: string paneId: string
object: ISheetObject<
PropTypeConfig_Compound<{
visible: PropTypeConfig_Boolean
data: DataType
}>
>
}> }>
} }
@ -53,9 +44,6 @@ export type IExtension = {
export type PaneInstance<ClassName extends string> = { export type PaneInstance<ClassName extends string> = {
extensionId: string extensionId: string
instanceId: string instanceId: string
object: ISheetObject<
PropTypeConfig_Compound<{data: $FixMe; visible: PropTypeConfig_Boolean}>
>
definition: PaneClassDefinition<$FixMe> definition: PaneClassDefinition<$FixMe>
} }
@ -87,6 +75,8 @@ export interface IStudio {
createPane<PaneClass extends string>( createPane<PaneClass extends string>(
paneClass: PaneClass, paneClass: PaneClass,
): PaneInstance<PaneClass> ): PaneInstance<PaneClass>
getStudioProject(): IProject
} }
export default class TheatreStudio implements IStudio { export default class TheatreStudio implements IStudio {
@ -163,6 +153,16 @@ export default class TheatreStudio implements IStudio {
return getStudio().scrub() return getStudio().scrub()
} }
getStudioProject() {
const core = getStudio().core
if (!core) {
throw new Error(`You're calling studio.getStudioProject() before \`@theatre/core\` is loaded. To fix this:
1. Check if \`@theatre/core\` is import/required in your bundle.
2. Check the stack trace of this error and make sure the funciton that calls getStudioProject() is run after \`@theatre/core\` is loaded.`)
}
return getStudio().getStudioProject(core)
}
debouncedScrub(threshold: number = 1000): Pick<IScrub, 'capture'> { debouncedScrub(threshold: number = 1000): Pick<IScrub, 'capture'> {
let currentScrub: IScrub | undefined let currentScrub: IScrub | undefined
const scheduleCommit = debounce(() => { const scheduleCommit = debounce(() => {

View file

@ -152,7 +152,7 @@ const Content: React.FC<{paneInstance: PaneInstance<$FixMe>}> = ({
</PanelDragZone> </PanelDragZone>
<F2> <F2>
<ErrorBoundary FallbackComponent={ErrorFallback}> <ErrorBoundary FallbackComponent={ErrorFallback}>
<Comp paneId={paneInstance.instanceId} object={paneInstance.object} /> <Comp paneId={paneInstance.instanceId} />
</ErrorBoundary> </ErrorBoundary>
</F2> </F2>
</Container> </Container>