import type { IProject , ISheet , ISheetObject } from '@theatre/core' ; import studioTicker from '@theatre/studio/studioTicker' ; import type { IDerivation , Pointer } from '@theatre/dataverse' ; import { prism } from '@theatre/dataverse' ; import SimpleCache from '@theatre/shared/utils/SimpleCache' ; import type { $IntentionalAny , VoidFn } from '@theatre/shared/utils/types' ; import type { IScrub } from '@theatre/studio/Scrub' ; import type { Studio } from '@theatre/studio/Studio' ; import { isSheetObjectPublicAPI , isSheetPublicAPI , } from '@theatre/shared/instanceTypes' ; import { getOutlineSelection } from './selectors' ; import type SheetObject from '@theatre/core/sheetObjects/SheetObject' ; import getStudio from './getStudio' ; import type React from 'react' ; import { debounce } from 'lodash-es' ; import type Sheet from '@theatre/core/sheets/Sheet' ; export interface ITransactionAPI { example param pointer param value set < V > ( pointer , value ) : void ; example param pointer unset < V > ( pointer ) : void ; } /**
 *
 */ export interface PaneClassDefinition { /**
     * Each pane has a `class`, which is a string.
     */ class : string ; /**
     * A react component that renders the content of the pane. It is given
     * a single prop, `paneId`, which is a unique identifier for the pane.
     *
     * If you wish to store and persist the state of the pane,
     * simply use a sheet and an object.
     */ component : React . ComponentType < { /**
         * The unique identifier of the pane
         */ paneId : string ; } > ; } /**
 * A Theatre.js Studio extension. You can define one either
 * in a separate package, or within your project.
 */ export interface IExtension { /**
     * Pick a unique ID for your extension. Ideally the name would be unique if
     * the extension was to be published to the npm repository.
     */ id : string ; example globalToolbar ? : { example component : React . ComponentType < { } > ; } ; example panes ? : Array < PaneClassDefinition > ; } export type PaneInstance < ClassName extends string > = { extensionId : string ; instanceId : string ; definition : PaneClassDefinition ; } ; export interface IStudioUI { /**
     * Temporarily hides the studio
     */ hide ( ) : void ; /**
     * Whether the studio is currently visible or hidden
     */ readonly isHidden : boolean ; /**
     * Makes the studio visible again.
     */ restore ( ) : void ; } export interface _StudioInitializeOpts { /**
     * The local storage key to use to persist the state.
     *
     * Default: "theatrejs:0.4"
     */ persistenceKey ? : string ; /**
     * Whether to persist the changes in the browser's temporary storage.
     * It is useful to set this to false in the test environment or when debugging things.
     *
     * Default: true
     */ usePersistentStorage ? : boolean ; } example example export interface IStudio { readonly ui : IStudioUI ; /**
     * Initializes the studio. Call it once in your index.js/index.ts module.
     * It silently ignores subsequent calls.
     */ initialize ( opts ? ) : void ; example transaction ( fn ) : void ; example scrub ( ) : IScrub ; param threshhold example debouncedScrub ( threshhold ) : Pick < IScrub , 'capture' > ; example setSelection ( selection ) : void ; /**
     * Calls fn every time the current selection changes.
     */ onSelectionChange ( fn ) : VoidFunction ; example readonly selection : Array < ISheetObject < { } > | ISheet > ; /**
     * Registers an extension
     */ extend ( /**
     * The extension's definition
     */ extension ) : void ; param paneClass createPane < PaneClass extends string > ( paneClass ) : PaneInstance < PaneClass > ; /**
     * Returns the Theatre.js project that contains the studio's sheets and objects.
     *
     * It is useful if you'd like to have sheets/objects that are present only when
     * studio is present.
     */ getStudioProject ( ) : IProject ; param projectId example createContentOfSaveFile ( projectId ) : Record < string , unknown > ; } export default class TheatreStudio implements IStudio { readonly ui = { hide ( ) { getStudio ( ) . ui . hide ( ) ; } , get isHidden ( ) : boolean { return getStudio ( ) . ui . isHidden ; } , restore ( ) { getStudio ( ) . ui . restore ( ) ; } , } ; private readonly _cache = new SimpleCache ( ) ; internal constructor ( internals ) { } initialize ( opts ? ) { const studio = getStudio ( ) ; return studio . initialize ( opts ) ; } extend ( extension ) { getStudio ( ) . extend ( extension ) ; } transaction ( fn ) { return getStudio ( ) . transaction ( ( { set , unset } ) => { return fn ( { set , unset } ) ; } ) ; } private _getSelectionDerivation ( ) { return this . _cache . get ( '_getStateDerivation()' , ( ) => prism ( ( ) : ( ISheetObject | ISheet ) [ ] => { return getOutlineSelection ( ) . filter ( ( s ) : s is SheetObject | Sheet => s . type === 'Theatre_SheetObject' || s . type === 'Theatre_Sheet' ) . map ( ( s ) => s . publicApi ) ; } ) ) ; } private _getSelection ( ) { return this . _getSelectionDerivation ( ) . getValue ( ) ; } setSelection ( selection ) { const sanitizedSelection = [ ... selection ] . filter ( ( s ) => isSheetObjectPublicAPI ( s ) || isSheetPublicAPI ( s ) ) . map ( ( s ) => getStudio ( ) . corePrivateAPI ! ( s ) ) ; getStudio ( ) . transaction ( ( { stateEditors } ) => { stateEditors . studio . historic . panels . outline . selection . set ( sanitizedSelection ) ; } ) ; } onSelectionChange ( fn ) { return this . _getSelectionDerivation ( ) . tapImmediate ( studioTicker , fn ) ; } get selection ( ) : Array < ISheetObject | ISheet > { return this . _getSelection ( ) ; } 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 = 1000 ) { let currentScrub ; const scheduleCommit = debounce ( ( ) => { const s = currentScrub ; if ( ! s ) return ; currentScrub = undefined ; s . commit ( ) ; } , threshold ) ; const capture = ( arg ) => { if ( ! currentScrub ) { currentScrub = this . scrub ( ) ; } let errored = true ; try { currentScrub . capture ( arg ) ; errored = false ; } finally { if ( errored ) { const s = currentScrub ; currentScrub = undefined ; s . discard ( ) ; } else { scheduleCommit ( ) ; } } } ; return { capture } ; } createPane < PaneClass extends string > ( paneClass ) { return getStudio ( ) . paneManager . createPane ( paneClass ) ; } destroyPane ( paneId ) { return getStudio ( ) . paneManager . destroyPane ( paneId ) ; } createContentOfSaveFile ( projectId ) { return getStudio ( ) . createContentOfSaveFile ( projectId ) as $IntentionalAny ; } }