Skip to content

Commit 1b94f46

Browse files
author
Yann Leflour
committed
Add iframe image grabber
1 parent aa47b79 commit 1b94f46

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

ui-sketcher-webview/src/PreviewShape.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-disable react-hooks/rules-of-hooks */
2+
import { RefObject, createRef } from "react";
23
import {
34
BaseBoxShapeUtil,
45
DefaultSpinner,
@@ -11,6 +12,7 @@ import {
1112
useValue,
1213
TLShapeId,
1314
createShapeId,
15+
SvgExportContext,
1416
} from "@tldraw/tldraw";
1517

1618
export type PreviewShape = TLBaseShape<
@@ -24,6 +26,7 @@ export type PreviewShape = TLBaseShape<
2426

2527
export class PreviewShapeUtil extends BaseBoxShapeUtil<PreviewShape> {
2628
static override type = "preview" as const;
29+
private iframeRef: RefObject<HTMLIFrameElement>;
2730

2831
getDefaultProps(): PreviewShape["props"] {
2932
return {
@@ -38,6 +41,57 @@ export class PreviewShapeUtil extends BaseBoxShapeUtil<PreviewShape> {
3841
override canResize = (_shape: PreviewShape) => true;
3942
override canBind = (_shape: PreviewShape) => false;
4043
override canUnmount = () => false;
44+
override toSvg(
45+
shape: PreviewShape,
46+
_ctx: SvgExportContext
47+
): SVGElement | Promise<SVGElement> {
48+
const g = document.createElementNS("http://www.w3.org/2000/svg", "g");
49+
// while screenshot is the same as the old one, keep waiting for a new one
50+
return new Promise((resolve, _) => {
51+
if (window === undefined) return resolve(g);
52+
53+
const windowListener = (event: MessageEvent) => {
54+
if (event.data.screenshot && event.data?.shapeid === shape.id) {
55+
const image = document.createElementNS(
56+
"http://www.w3.org/2000/svg",
57+
"image"
58+
);
59+
image.setAttributeNS(
60+
"http://www.w3.org/1999/xlink",
61+
"href",
62+
event.data.screenshot
63+
);
64+
image.setAttribute("width", shape.props.w.toString());
65+
image.setAttribute("height", shape.props.h.toString());
66+
g.appendChild(image);
67+
window.removeEventListener("message", windowListener);
68+
clearTimeout(timeOut);
69+
resolve(g);
70+
}
71+
};
72+
73+
const timeOut = setTimeout(() => {
74+
resolve(g);
75+
window.removeEventListener("message", windowListener);
76+
}, 2000);
77+
window.addEventListener("message", windowListener);
78+
//request new screenshot
79+
80+
if (this.iframeRef.current?.contentWindow) {
81+
this.iframeRef.current.contentWindow.postMessage(
82+
{ action: "take-screenshot", shapeid: shape.id },
83+
"*"
84+
);
85+
} else {
86+
console.log("iframe not found or not accessible");
87+
}
88+
});
89+
}
90+
91+
constructor(editor: Editor) {
92+
super(editor);
93+
this.iframeRef = createRef();
94+
}
4195

4296
override component(shape: PreviewShape) {
4397
const boxShadow = useValue(
@@ -74,6 +128,7 @@ export class PreviewShapeUtil extends BaseBoxShapeUtil<PreviewShape> {
74128
) : (
75129
<>
76130
<iframe
131+
ref={this.iframeRef}
77132
src={source}
78133
width={toDomPrecision(shape.props.w)}
79134
height={toDomPrecision(shape.props.h)}

0 commit comments

Comments
 (0)