1
1
/* eslint-disable react-hooks/rules-of-hooks */
2
+ import { RefObject , createRef } from "react" ;
2
3
import {
3
4
BaseBoxShapeUtil ,
4
5
DefaultSpinner ,
@@ -11,6 +12,7 @@ import {
11
12
useValue ,
12
13
TLShapeId ,
13
14
createShapeId ,
15
+ SvgExportContext ,
14
16
} from "@tldraw/tldraw" ;
15
17
16
18
export type PreviewShape = TLBaseShape <
@@ -24,6 +26,7 @@ export type PreviewShape = TLBaseShape<
24
26
25
27
export class PreviewShapeUtil extends BaseBoxShapeUtil < PreviewShape > {
26
28
static override type = "preview" as const ;
29
+ private iframeRef : RefObject < HTMLIFrameElement > ;
27
30
28
31
getDefaultProps ( ) : PreviewShape [ "props" ] {
29
32
return {
@@ -38,6 +41,57 @@ export class PreviewShapeUtil extends BaseBoxShapeUtil<PreviewShape> {
38
41
override canResize = ( _shape : PreviewShape ) => true ;
39
42
override canBind = ( _shape : PreviewShape ) => false ;
40
43
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
+ }
41
95
42
96
override component ( shape : PreviewShape ) {
43
97
const boxShadow = useValue (
@@ -74,6 +128,7 @@ export class PreviewShapeUtil extends BaseBoxShapeUtil<PreviewShape> {
74
128
) : (
75
129
< >
76
130
< iframe
131
+ ref = { this . iframeRef }
77
132
src = { source }
78
133
width = { toDomPrecision ( shape . props . w ) }
79
134
height = { toDomPrecision ( shape . props . h ) }
0 commit comments