import React from "react" ; import Blockly from "blockly" ; import debounce from "./debounce" ; function importFromXml ( xml , workspace , onImportXmlError ) { try { Blockly . Xml . domToWorkspace ( Blockly . Xml . textToDom ( xml ) , workspace ) ; return true ; } catch ( e ) { if ( onImportXmlError ) { onImportXmlError ( e ) ; } return false ; } } const useBlocklyWorkspace = ( { ref , initialXml , toolboxConfiguration , workspaceConfiguration , onWorkspaceChange , onImportXmlError , onInject , onDispose , } ) => { const [ workspace , setWorkspace ] = React . useState ( null ) ; const [ xml , setXml ] = React . useState ( initialXml ) ; const [ didInitialImport , setDidInitialImport ] = React . useState ( false ) ; const [ didHandleNewWorkspace , setDidHandleNewWorkspace ] = React . useState ( false ) ; const workspaceConfigurationRef = React . useRef ( workspaceConfiguration ) ; React . useEffect ( ( ) => { workspaceConfigurationRef . current = workspaceConfiguration ; } , [ workspaceConfiguration ] ) ; const toolboxConfigurationRef = React . useRef ( toolboxConfiguration ) ; React . useEffect ( ( ) => { toolboxConfigurationRef . current = toolboxConfiguration ; if ( toolboxConfiguration && workspace ) { workspace . updateToolbox ( toolboxConfiguration ) ; } } , [ toolboxConfiguration , workspace ] ) ; const onInjectRef = React . useRef ( onInject ) ; const onDisposeRef = React . useRef ( onDispose ) ; React . useEffect ( ( ) => { onInjectRef . current = onInject ; } , [ onInject ] ) ; React . useEffect ( ( ) => { onDisposeRef . current = onDispose ; } , [ onDispose ] ) ; const handleWorkspaceChanged = React . useCallback ( ( newWorkspace ) => { if ( onWorkspaceChange ) { onWorkspaceChange ( newWorkspace ) ; } } , [ onWorkspaceChange ] ) ; React . useEffect ( ( ) => { const newWorkspace = Blockly . inject ( ref . current , { ... workspaceConfigurationRef . current , toolbox : toolboxConfigurationRef . current , } ) ; setWorkspace ( newWorkspace ) ; setDidInitialImport ( false ) ; setDidHandleNewWorkspace ( false ) ; if ( onInjectRef . current ) { onInjectRef . current ( newWorkspace ) ; } const onDisposeFunction = onDisposeRef . current ; return ( ) => { newWorkspace . dispose ( ) ; if ( onDisposeFunction ) { onDisposeFunction ( newWorkspace ) ; } } ; } , [ ref ] ) ; React . useEffect ( ( ) => { if ( workspace && ! didHandleNewWorkspace ) { handleWorkspaceChanged ( workspace ) ; } } , [ handleWorkspaceChanged , didHandleNewWorkspace , workspace ] ) ; React . useEffect ( ( ) => { if ( workspace == null ) { return undefined ; } const listener = ( ) => { handleWorkspaceChanged ( workspace ) ; } ; workspace . addChangeListener ( listener ) ; return ( ) => { workspace . removeChangeListener ( listener ) ; } ; } , [ workspace , handleWorkspaceChanged ] ) ; React . useEffect ( ( ) => { if ( workspace == null ) { return undefined ; } const [ callback , cancel ] = debounce ( ( ) => { const newXml = Blockly . Xml . domToText ( Blockly . Xml . workspaceToDom ( workspace ) ) ; if ( newXml === xml ) { return ; } setXml ( newXml ) ; } , 200 ) ; workspace . addChangeListener ( callback ) ; return ( ) => { workspace . removeChangeListener ( callback ) ; cancel ( ) ; } ; } , [ workspace , xml ] ) ; React . useEffect ( ( ) => { if ( xml && workspace && ! didInitialImport ) { const success = importFromXml ( xml , workspace , onImportXmlError ) ; if ( ! success ) { setXml ( null ) ; } setDidInitialImport ( true ) ; } } , [ xml , workspace , didInitialImport , onImportXmlError ] ) ; return { workspace , xml } ; } ; export default useBlocklyWorkspace ;