make sure we always catch the iframe when its fully loaded

This commit is contained in:
Oleg Isonen committed 2022-09-17 17:17:55 +02:00
1 parent 589ca862f6
commit 6d359b878c
5 files changed
+41 -8

No files matched your search

+2 -2
View File
@@ -46,7 +46,7 @@ import { usePublishScrollState } from "./shared/use-publish-scroll-state";
import { useDragAndDrop } from "./shared/use-drag-drop";
import { setInstanceChildrenMutable } from "~/shared/tree-utils";
import { CanvasData } from "~/shared/db";
import { useDesignerReady } from "./shared/use-designer-ready";
import { useSubscribeDesignerReady } from "./shared/use-designer-ready";
registerContainers();
@@ -119,7 +119,7 @@ export const Canvas = ({ data }: CanvasProps): JSX.Element | null => {
if (data.tree === null) {
throw new Error("Tree is null");
}
const isDesignerReady = useDesignerReady();
const isDesignerReady = useSubscribeDesignerReady();
useInitializeBreakpoints(data.breakpoints);
globalStyles();
useAllUserProps(data.props);
@@ -7,7 +7,7 @@ declare module "~/shared/pubsub" {
}
}
export const useDesignerReady = () => {
export const useSubscribeDesignerReady = () => {
const [isReady, setIsReady] = useState<boolean>(false);
useSubscribe("designerReady", () => {
setIsReady(true);
+21 -5
View File
@@ -1,4 +1,4 @@
import { useCallback } from "react";
import { useCallback, useEffect, useState } from "react";
import { type Publish, usePublish, useSubscribe } from "~/shared/pubsub";
import type { Project } from "@webstudio-is/project";
import type { Config } from "~/config";
@@ -33,6 +33,7 @@ import {
import { useClientSettings } from "./shared/client-settings";
import { Navigator } from "./features/sidebar-left";
import { PANEL_WIDTH } from "./shared/constants";
import { onLoad } from "~/shared/dom-utils";
export const links = () => {
return [
@@ -68,6 +69,22 @@ const useNavigatorLayout = () => {
return isLoaded ? clientSettings.navigatorLayout : "docked";
};
const usePublishDesignerReady = (publish: Publish) => {
const [ref, setRef] = useState(null);
useEffect(() => {
if (ref === null) return;
onLoad(ref).then(() => {
// We publish this even to let canvas know that we are now listening to the events, otherwise if canvas loads faster than designer, which is possible with SSR,
// we can miss the events and designer will just not connect to the canvas.
publish({ type: "designerReady" });
});
}, [ref, publish]);
return setRef;
};
type SidePanelProps = {
children: JSX.Element | Array<JSX.Element>;
isPreviewMode: boolean;
@@ -226,17 +243,16 @@ export const Designer = ({ config, project }: DesignerProps) => {
const onRefReadCanvasWidth = useUpdateCanvasWidth();
const { onRef: onRefReadCanvas, onTransitionEnd } = useReadCanvasRect();
const [dragAndDropState] = useDragAndDropState();
const onRefIframeReady = usePublishDesignerReady(publish);
const iframeRefCallback = useCallback(
(ref) => {
publishRef.current = ref;
onRefReadCanvasWidth(ref);
onRefReadCanvas(ref);
// We publish this even to let canvas know that we are now listening to the events, otherwise if canvas loads faster than designer, which is possible with SSR,
// we can miss the events and designer will just not connect to the canvas.
publish({ type: "designerReady" });
onRefIframeReady(ref);
},
[publishRef, onRefReadCanvasWidth, onRefReadCanvas, publish]
[publishRef, onRefReadCanvasWidth, onRefReadCanvas, onRefIframeReady]
);
return (
@@ -1 +1,2 @@
export * from "./instance";
export * from "./on-iframe-load";
@@ -0,0 +1,16 @@
/**
* Resolve a promise when an iframe has readyState complete.
* Checks periodically for the readyState to be complete, because somttimes the load event may simply not fire for various reasons.
*/
export const onLoad = (iframe: HTMLIFrameElement) =>
new Promise((resolve) => {
if (iframe === null) return;
const check = () => {
if (document.readyState === "complete") {
clearInterval(intervalId);
resolve("complete");
}
};
iframe.addEventListener("load", check);
const intervalId = setInterval(check, 100);
});