From 970f5b25bdfcee81068fa9b3114d26baf987fede Mon Sep 17 00:00:00 2001 From: Danny McGee Date: Tue, 5 Mar 2024 18:04:41 -0500 Subject: [PATCH] Communication bridge to `storyteller-frontend` (#74) This PR establishes a rudimentary communication protocol between Storyteller Studio and the parent application (at fakeyou.com / storyteller.ai) via the `Window.postMessage` API. An example of how this protocol can be used from the parent application is here: https://github.com/storytold/storyteller-frontend/commit/d36e2a9e5c162233d7bd194fdbaa26199bbf6f7a --- studio-frontend/src/app/app.element.ts | 19 ++++- studio-web/src/index.ts | 1 + .../lib/iframe-messaging-bridge.element.ts | 70 +++++++++++++++++++ tsconfig.base.json | 1 + 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 studio-web/src/lib/iframe-messaging-bridge.element.ts diff --git a/studio-frontend/src/app/app.element.ts b/studio-frontend/src/app/app.element.ts index b55927b..9212f25 100644 --- a/studio-frontend/src/app/app.element.ts +++ b/studio-frontend/src/app/app.element.ts @@ -24,6 +24,7 @@ import "@storyteller/studio-ui/toolbar"; import "@storyteller/studio-ui/tree"; import "@storyteller/studio-web/canvas-provider"; import "@storyteller/studio-web/entity-inspector"; +import "@storyteller/studio-web/iframe-messaging-bridge"; import "@storyteller/studio-web/loading"; import "@storyteller/studio-web/scene-hierarchy"; import "@storyteller/studio-web/studio"; @@ -71,7 +72,21 @@ export class AppElement extends LitElement { headers: { "Accept": "text/plain" }, body: formData, }); - console.log(response); + + if (response.ok) { + const resultJson: { + success: boolean; + media_file_token: string; + } = await response.json(); + + if (resultJson.success) { + this.dispatchEvent(new CustomEvent("scene-uploaded", { + detail: resultJson.media_file_token, + bubbles: true, + composed: true, + })); + } + } } catch (err) { console.error(err); @@ -132,6 +147,8 @@ export class AppElement extends LitElement { protected override render = () => html` + + ): void { + if (!this.#parentOrigin || event.origin !== this.#parentOrigin) + return; + + if (event.data === "save-scene") + studio.saveScene(); + } + + @on("window:scene-uploaded") + onSceneUploaded(event: CustomEvent): void { + if (!this.#parentWindow || !this.#parentOrigin) + return; + + this.#parentWindow.postMessage(`scene-saved:${event.detail}`, this.#parentOrigin); + } + + @on("window:scene-state") + onSceneStateChange({ detail: state }: SceneStateEvent): void { + if (!this.#parentWindow || !this.#parentOrigin) + return; + + if (state === SceneState.Active) + this.#parentWindow.postMessage("studio-ready", this.#parentOrigin); + } + + protected override render = () => nothing; +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 9b8ac87..e4c0493 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -27,6 +27,7 @@ "@storyteller/studio-web": ["studio-web/src/index.ts"], "@storyteller/studio-web/canvas-provider": ["studio-web/src/lib/canvas-provider.element.ts"], "@storyteller/studio-web/entity-inspector": ["studio-web/src/lib/inspector/entity-inspector.element.ts"], + "@storyteller/studio-web/iframe-messaging-bridge": ["studio-web/src/lib/iframe-messaging-bridge.element.ts"], "@storyteller/studio-web/loading": ["studio-web/src/lib/loading.element.ts"], "@storyteller/studio-web/scene-data-provider": ["studio-web/src/lib/scene-data-provider.element.ts"], "@storyteller/studio-web/scene-hierarchy": ["studio-web/src/lib/scene-hierarchy.element.ts"],