Extensions can now use studio's project for editing-related objects.
This commit is contained in:
parent
828fbb97b5
commit
b08588e9d6
4 changed files with 91 additions and 104 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue