1- import React , { useState , useEffect , useRef } from 'react' ;
2- import { Spring } from 'react-spring/renderprops' ;
3- import { ThemeProvider } from 'styled-components' ;
4- import history from 'app/utils/history' ;
5- import { ESC , ENTER } from '@codesandbox/common/lib/utils/keycodes' ;
1+ import Portal from '@codesandbox/common/lib/components/Portal' ;
62import theme from '@codesandbox/common/lib/theme' ;
3+ import { Template } from '@codesandbox/common/lib/types' ;
4+ import { ENTER , ESC } from '@codesandbox/common/lib/utils/keycodes' ;
75import { sandboxUrl } from '@codesandbox/common/lib/utils/url-generator' ;
8- import Portal from '@codesandbox/common/lib/components/Portal' ;
6+ import React , {
7+ FunctionComponent ,
8+ HTMLAttributes ,
9+ useEffect ,
10+ useRef ,
11+ useState ,
12+ } from 'react' ;
13+ import { Spring } from 'react-spring/renderprops' ;
14+ import { ThemeProvider } from 'styled-components' ;
15+
916import { useOvermind } from 'app/overmind' ;
17+ import history from 'app/utils/history' ;
1018
1119import {
20+ AnimatedModalContainer ,
1221 ButtonsContainer ,
1322 Container ,
14- AnimatedModalContainer ,
1523 ContainerLink ,
1624 DarkBG ,
1725} from './elements' ;
18-
1926import { NewSandboxModal } from './NewSandboxModal' ;
2027
21- interface CreateNewSandboxProps {
22- style : React . CSSProperties ;
23- collectionId ?: string ;
24- mostUsedSandboxTemplate : {
25- [ key : string ] : any ;
26- } ;
27- }
28+ const DEFAULT_RECT = { height : 0 , width : 0 , x : 0 , y : 0 } ;
2829
29- const CreateNewSandbox : React . SFC < CreateNewSandboxProps > = ( {
30- style,
30+ type Props = {
31+ collectionId ?: string ;
32+ mostUsedSandboxTemplate : Template ;
33+ } & Pick < HTMLAttributes < HTMLDivElement > , 'style' > ;
34+ export const CreateNewSandbox : FunctionComponent < Props > = ( {
3135 collectionId,
3236 mostUsedSandboxTemplate,
37+ style,
3338} ) => {
3439 const {
3540 actions : {
3641 dashboard : { createSandboxClicked } ,
3742 } ,
3843 } = useOvermind ( ) ;
39-
40- const [ creating , setCreating ] = useState ( false ) ;
4144 const [ closingCreating , setClosingCreating ] = useState ( false ) ;
45+ const [ creating , setCreating ] = useState ( false ) ;
4246 const [ forking , setForking ] = useState ( false ) ;
47+ const ref = useRef < HTMLDivElement > ( null ) ;
48+ const toRef = useRef < HTMLDivElement > ( null ) ;
4349
44- const ref = useRef ( null ) ;
45- const toRef = useRef ( null ) ;
50+ useEffect ( ( ) => {
51+ const keydownListener = ( { keyCode } : KeyboardEvent ) => {
52+ if ( keyCode === ESC ) {
53+ close ( ) ;
54+ }
55+ } ;
56+
57+ document . addEventListener ( 'keydown' , keydownListener ) ;
58+
59+ return ( ) => document . removeEventListener ( 'keydown' , keydownListener ) ;
60+ } , [ ] ) ;
4661
4762 const close = ( ) => {
4863 setClosingCreating ( true ) ;
64+
4965 setTimeout ( ( ) => {
5066 setClosingCreating ( false ) ;
5167 setCreating ( false ) ;
5268 } , 500 ) ;
5369 } ;
54-
55- useEffect ( ( ) => {
56- const keydownListener = e => {
57- if ( e . keyCode === ESC ) {
58- close ( ) ;
59- }
60- } ;
61- document . addEventListener ( 'keydown' , keydownListener ) ;
62- return ( ) => {
63- document . removeEventListener ( 'keydown' , keydownListener ) ;
64- } ;
65- } , [ ] ) ;
66-
67- const createSandbox = ( template : { [ key : string ] : any } ) => {
70+ const createSandbox = ( { shortid } : Template ) => {
6871 setForking ( true ) ;
69- if ( ! collectionId ) {
72+
73+ if ( collectionId ) {
74+ createSandboxClicked ( { body : { collectionId } , sandboxId : shortid } ) ;
75+ } else {
7076 setTimeout ( ( ) => {
71- history . push ( sandboxUrl ( { id : template . shortid } ) ) ;
77+ history . push ( sandboxUrl ( { id : shortid } ) ) ;
7278 } , 300 ) ;
73- } else {
74- createSandboxClicked ( {
75- sandboxId : template . shortid ,
76- body : {
77- collectionId,
78- } ,
79- } ) ;
8079 }
8180 } ;
82-
8381 const handleClick = ( ) => {
8482 setCreating ( true ) ;
8583 } ;
8684
87- const fromRects = ref . current ? ref . current . getBoundingClientRect ( ) : { } ;
88- const toRects = toRef . current ? toRef . current . getBoundingClientRect ( ) : { } ;
89-
90- let usedRects = [
91- {
92- position : 'fixed' ,
93- top : toRects . y ,
94- left : toRects . x ,
95- height : toRects . height ,
96- width : toRects . width ,
97- overflow : 'hidden' ,
98- } ,
99- {
100- position : 'fixed' ,
101- left : fromRects . x ,
102- top : fromRects . y ,
103- width : fromRects . width + 32 ,
104- height : fromRects . height + 32 ,
105- overflow : 'hidden' ,
106- } ,
107- ] ;
108-
109- if ( ! closingCreating ) {
110- usedRects = usedRects . reverse ( ) ;
111- }
85+ const buttonName = `Create ${ mostUsedSandboxTemplate . niceName } Sandbox` ;
86+ const mostUsedSandboxComponent = collectionId ? (
87+ < Container
88+ color = { mostUsedSandboxTemplate . color }
89+ onClick = { ( ) => createSandbox ( mostUsedSandboxTemplate ) }
90+ ref = { ref }
91+ role = "button"
92+ tabIndex = { 0 }
93+ >
94+ { buttonName }
95+ </ Container >
96+ ) : (
97+ < ContainerLink
98+ color = { mostUsedSandboxTemplate . color }
99+ to = { sandboxUrl ( { id : mostUsedSandboxTemplate . shortid } ) }
100+ >
101+ { buttonName }
102+ </ ContainerLink >
103+ ) ;
112104
113- let mostUsedSandboxComponent ;
114- if ( mostUsedSandboxTemplate ) {
115- const buttonName = `Create ${ mostUsedSandboxTemplate . niceName } Sandbox` ;
116- if ( collectionId ) {
117- mostUsedSandboxComponent = (
118- < Container
119- ref = { ref }
120- onClick = { ( ) => createSandbox ( mostUsedSandboxTemplate ) }
121- color = { mostUsedSandboxTemplate . color }
122- tabIndex = { 0 }
123- role = "button"
124- hide = { false }
125- >
126- { buttonName }
127- </ Container >
128- ) ;
129- } else {
130- mostUsedSandboxComponent = (
131- < ContainerLink
132- to = { sandboxUrl ( { id : mostUsedSandboxTemplate . shortid } ) }
133- color = { mostUsedSandboxTemplate . color }
134- >
135- { buttonName }
136- </ ContainerLink >
137- ) ;
138- }
139- }
105+ const fromRectDOM = ref . current
106+ ? ref . current . getBoundingClientRect ( )
107+ : DEFAULT_RECT ;
108+ const fromRect = {
109+ position : 'fixed' ,
110+ left : fromRectDOM . x ,
111+ top : fromRectDOM . y ,
112+ width : fromRectDOM . width + 32 ,
113+ height : fromRectDOM . height + 32 ,
114+ overflow : 'hidden' ,
115+ } ;
116+ const toRectDOM = toRef . current
117+ ? toRef . current . getBoundingClientRect ( )
118+ : DEFAULT_RECT ;
119+ const toRect = {
120+ position : 'fixed' ,
121+ top : toRectDOM . y ,
122+ left : toRectDOM . x ,
123+ height : toRectDOM . height ,
124+ width : toRectDOM . width ,
125+ overflow : 'hidden' ,
126+ } ;
140127
141128 return (
142129 < >
143130 { creating && (
144131 < >
145132 < Portal >
146- < DarkBG onClick = { close } closing = { closingCreating } />
133+ < DarkBG closing = { closingCreating } onClick = { close } />
147134 </ Portal >
135+
148136 < Portal >
149137 < ThemeProvider theme = { theme } >
150- < Spring native from = { usedRects [ 0 ] } to = { usedRects [ 1 ] } >
138+ < Spring
139+ from = { closingCreating ? toRect : fromRect }
140+ native
141+ to = { closingCreating ? fromRect : toRect }
142+ >
151143 { newStyle => (
152144 < AnimatedModalContainer
153- tabIndex = { - 1 }
154- aria-modal = "true"
155145 aria-labelledby = "new-sandbox"
156- forking = { forking || undefined }
146+ aria-modal = "true"
147+ forking = { forking }
157148 // @ts -ignore
158149 style = {
159150 forking
@@ -166,12 +157,12 @@ const CreateNewSandbox: React.SFC<CreateNewSandboxProps> = ({
166157 }
167158 : newStyle
168159 }
160+ tabIndex = { - 1 }
169161 >
170162 < NewSandboxModal
171- width = { toRects . width }
172- forking = { forking }
173163 closing = { closingCreating }
174164 createSandbox = { createSandbox }
165+ forking = { forking }
175166 />
176167 </ AnimatedModalContainer >
177168 ) }
@@ -184,21 +175,23 @@ const CreateNewSandbox: React.SFC<CreateNewSandboxProps> = ({
184175 < div style = { style } >
185176 < ButtonsContainer >
186177 < Container
187- ref = { ref }
188- onClick = { handleClick }
189- tabIndex = { 0 }
190- role = "button"
191178 hide = { creating }
192- onKeyDown = { e => {
193- if ( e . keyCode === ENTER ) {
179+ onClick = { handleClick }
180+ onKeyDown = { ( { keyCode } : React . KeyboardEvent < HTMLDivElement > ) => {
181+ if ( keyCode === ENTER ) {
194182 handleClick ( ) ;
195183 }
196184 } }
185+ ref = { ref }
186+ role = "button"
187+ tabIndex = { 0 }
197188 >
198189 Create Sandbox
199190 </ Container >
191+
200192 { mostUsedSandboxComponent }
201193 </ ButtonsContainer >
194+
202195 < Portal >
203196 < div
204197 style = { {
@@ -216,12 +209,10 @@ const CreateNewSandbox: React.SFC<CreateNewSandboxProps> = ({
216209 width : 950 ,
217210 } }
218211 >
219- < div ref = { toRef } style = { { width : '100%' , height : '100%' } } />
212+ < div ref = { toRef } style = { { height : '100%' , width : '100%' } } />
220213 </ div >
221214 </ Portal >
222215 </ div >
223216 </ >
224217 ) ;
225218} ;
226-
227- export default CreateNewSandbox ;
0 commit comments