1- import { useEffect , useState } from "react" ;
1+ import { type ReactNode , useEffect , useState } from "react" ;
22import { createPortal } from "react-dom" ;
33import type { Editor } from "tldraw" ;
44import { asCanvasTarget , type CanvasTarget } from "./canvasClicks" ;
@@ -9,33 +9,18 @@ import { useCanvasFileHtml } from "./canvasLibrary";
99const INSET = 32 ;
1010
1111/**
12- * Space on a selected board or picture shows it alone over the whole window, the window dimmed
13- * round the board, which is scaled to fit it. Space again, or Esc, comes back to the canvas
14- * as it was. Inside the window rather than the browser's full screen, which on a Mac moves the
15- * window to a display of its own and back, slowly.
16- *
17- * In the window's document, not the canvas frame's, so it covers the tab bar and the chat as well
18- * (the window loads the same stylesheet, shell.tsx). Taken from tldraw on the key going down, so
19- * with one of them selected Space is this and not the hand. Heard in both documents: clicking the
20- * shown board moves the focus out of the frame.
12+ * Space on a selected board or picture shows it alone over the whole window (`Present`), scaled
13+ * to fit it. Taken from tldraw on the key going down, so with one of them selected Space is this
14+ * and not the hand.
2115 */
2216export function CanvasPresent ( { editor } : { editor : Editor | null } ) {
2317 const [ shown , setShown ] = useState < CanvasTarget > ( ) ;
2418 const top = window . top ! ;
2519 const [ view , setView ] = useState ( { w : top . innerWidth , h : top . innerHeight } ) ;
2620
2721 useEffect ( ( ) => {
28- if ( ! editor ) return ;
22+ if ( ! editor || shown ) return ;
2923 const onDown = ( e : KeyboardEvent ) => {
30- if ( shown ) {
31- if ( e . code !== "Space" && e . key !== "Escape" ) return ;
32- e . preventDefault ( ) ;
33- e . stopPropagation ( ) ;
34- if ( e . repeat ) return ;
35- setShown ( undefined ) ;
36- editor . focus ( ) ;
37- return ;
38- }
3924 if ( e . code !== "Space" || e . repeat ) return ;
4025 const typing =
4126 e . target instanceof HTMLElement &&
@@ -50,20 +35,66 @@ export function CanvasPresent({ editor }: { editor: Editor | null }) {
5035 e . stopPropagation ( ) ;
5136 setShown ( target ) ;
5237 } ;
38+ addEventListener ( "keydown" , onDown , true ) ;
39+ return ( ) => removeEventListener ( "keydown" , onDown , true ) ;
40+ } , [ editor , shown ] ) ;
41+
42+ useEffect ( ( ) => {
5343 const resized = ( ) => setView ( { w : top . innerWidth , h : top . innerHeight } ) ;
44+ top . addEventListener ( "resize" , resized ) ;
45+ return ( ) => top . removeEventListener ( "resize" , resized ) ;
46+ } , [ top ] ) ;
47+
48+ if ( ! editor || ! shown ) return null ;
49+ return (
50+ < Present
51+ close = { ( ) => {
52+ setShown ( undefined ) ;
53+ editor . focus ( ) ;
54+ } }
55+ >
56+ < Presented editor = { editor } shape = { shown } view = { view } />
57+ </ Present >
58+ ) ;
59+ }
60+
61+ /**
62+ * Something shown alone over the whole window, the window dimmed round it: a board or picture
63+ * from the canvas, or a picture in the chat. Space, Esc or a click beside it comes back to where
64+ * it was. Inside the window rather than the browser's full screen, which on a Mac moves the window
65+ * to a display of its own and back, slowly.
66+ *
67+ * In the window's document, not the canvas frame's, so it covers the tab bar and the chat as well
68+ * (the window loads the same stylesheet, shell.tsx). The keys are heard in both documents: the
69+ * focus can be in either.
70+ */
71+ export function Present ( {
72+ close,
73+ children,
74+ } : {
75+ close : ( ) => void ;
76+ children : ReactNode ;
77+ } ) {
78+ const top = window . top ! ;
79+ useEffect ( ( ) => {
80+ const onDown = ( e : KeyboardEvent ) => {
81+ if ( e . code !== "Space" && e . key !== "Escape" ) return ;
82+ e . preventDefault ( ) ;
83+ e . stopPropagation ( ) ;
84+ if ( ! e . repeat ) close ( ) ;
85+ } ;
5486 const windows = top === window ? [ window ] : [ window , top ] ;
5587 for ( const w of windows ) w . addEventListener ( "keydown" , onDown , true ) ;
56- top . addEventListener ( "resize" , resized ) ;
5788 return ( ) => {
5889 for ( const w of windows ) w . removeEventListener ( "keydown" , onDown , true ) ;
59- top . removeEventListener ( "resize" , resized ) ;
6090 } ;
61- } , [ editor , shown , top ] ) ;
62-
63- if ( ! editor || ! shown ) return null ;
91+ } , [ close , top ] ) ;
6492 return createPortal (
65- < div className = "sp-present" >
66- < Presented editor = { editor } shape = { shown } view = { view } />
93+ < div
94+ className = "sp-present"
95+ onClick = { ( e ) => e . target === e . currentTarget && close ( ) }
96+ >
97+ { children }
6798 </ div > ,
6899 top . document . body ,
69100 ) ;
0 commit comments