diff --git a/README.md b/README.md
index 1a30afa..73c9fd8 100644
--- a/README.md
+++ b/README.md
@@ -117,11 +117,15 @@ function MyBlocklyHookEmbed() {
All properties are optional.
* `initialXml`: The XML of the program to initially load in the editor.
+* `initialJson`: The JSON of the program to initially load in the editor.
+* `updateXml`: A reference to XML of the program. If this value is changed (i.e. external to the BlocklyWorkspace component or useBlocklyWorkspace hook), the Blockly workspace will update to reflect the new XML.
+* `updateJson`: A reference to JSON of the program. If this value is changed (i.e. external to the BlocklyWorkspace component or useBlocklyWorkspace hook), the Blockly workspace will update to reflect the new JSON.
* `workspaceConfiguration`: Any configuration options to be passed into `Blockly.inject` (except for `toolbox`, which is a separate prop).
* `toolboxConfiguration`: A JSON toolbox configuration (see [the Blockly documentation](https://developers.google.com/blockly/guides/configure/web/toolbox#json) for details on this format).
* `className`: The value for the `class` attribute to be used on the `
` elements generated by this component. Typically you'll need to use this to set the height of the Blockly editor, using either an explicit `height` style, flexboxes, or some other means.
* `onWorkspaceChange`: A function called every time the content of the workspace changes. It should take a single argument, which is the Blockly workspace object. (You can call methods such as Blockly.JavaScript.workspaceToCode on this object.)
-* `onXmlChange`: A function called every time the content of the workspace, debounced to be called at most once every 200 milliseconds. This function should take a single argument, which is the new XML generated from the workspace.
+* `onXmlChange`: A function called every time the content of the workspace changes, debounced to be called at most once every 200 milliseconds. This function should take a single argument, which is the new XML generated from the workspace.
+* `onJsonChange`: A function called every time the content of the workspace changes, debounced to be called at most once every 200 milliseconds. This function should take a single argument, which is the new JSON generated from the workspace.
* `onImportXmlError`: A function called if `initialXml` can't be imported. This function takes a single argument, which is the error thrown during XML import.
* `onInject`: A function called after the Blockly workspace is injected. This function takes a single argument, which is the newly-injected Blockly workspace object. This is a good place to add Blockly plugins, if desired.
* `onDispose`: A function called after the Blockly workspace is disposed and removed from the page. This function takes a single argument, which is the just-disposed Blockly workspace object. Some Blockly plugins need to use this to dispose their own resources.
diff --git a/src/BlocklyWorkspace.tsx b/src/BlocklyWorkspace.tsx
index 0e48076..8c864b2 100644
--- a/src/BlocklyWorkspace.tsx
+++ b/src/BlocklyWorkspace.tsx
@@ -6,6 +6,8 @@ import { BlocklyWorkspaceProps } from "./BlocklyWorkspaceProps";
const propTypes = {
initialXml: PropTypes.string,
initialJson: PropTypes.object,
+ updateXml: PropTypes.string,
+ updateJson: PropTypes.object,
toolboxConfiguration: PropTypes.object, // eslint-disable-line react/forbid-prop-types
workspaceConfiguration: PropTypes.object, // eslint-disable-line react/forbid-prop-types
className: PropTypes.string,
@@ -21,6 +23,8 @@ const propTypes = {
function BlocklyWorkspace({
initialXml,
initialJson,
+ updateXml,
+ updateJson,
toolboxConfiguration,
workspaceConfiguration,
className,
@@ -37,6 +41,8 @@ function BlocklyWorkspace({
ref: editorDiv,
initialXml,
initialJson,
+ updateXml,
+ updateJson,
toolboxConfiguration,
workspaceConfiguration,
onWorkspaceChange,
@@ -44,6 +50,7 @@ function BlocklyWorkspace({
onImportError,
onInject,
onDispose,
+
});
const onXmlChangeRef = React.useRef(onXmlChange);
React.useEffect(() => {
diff --git a/src/BlocklyWorkspaceProps.ts b/src/BlocklyWorkspaceProps.ts
index ed5ef59..1d566d4 100644
--- a/src/BlocklyWorkspaceProps.ts
+++ b/src/BlocklyWorkspaceProps.ts
@@ -5,6 +5,8 @@ import { RefObject } from "react";
export interface CommonBlocklyProps {
initialXml?: string;
initialJson?: object;
+ updateXml?: string;
+ updateJson?: object;
toolboxConfiguration?: Blockly.utils.toolbox.ToolboxDefinition;
workspaceConfiguration: Blockly.BlocklyOptions;
onWorkspaceChange?: (workspace: WorkspaceSvg) => void;
diff --git a/src/dev-index.tsx b/src/dev-index.tsx
index fd5afc4..e077414 100644
--- a/src/dev-index.tsx
+++ b/src/dev-index.tsx
@@ -15,6 +15,8 @@ const TestEditor = () => {
const [generatedXml, setGeneratedXml] = useState("");
const [generatedJson, setGeneratedJson] = useState("");
const [generatedCode, setGeneratedCode] = useState("");
+ const [updateXml, setUpdateXml] = useState("");
+ const [updateJson, setUpdateJson] = useState({});
React.useEffect(() => {
window.setTimeout(() => {
@@ -85,7 +87,7 @@ const TestEditor = () => {
const [serialState, setSerialState] = useState<"XML" | "JSON">("XML");
return (
<>
-