11import React from 'react' ;
22import { useLocation } from 'react-router-dom' ;
3+ import { motion } from 'framer-motion' ;
34import { useOvermind } from 'app/overmind' ;
45import { sandboxUrl } from '@codesandbox/common/lib/utils/url-generator' ;
56import { ESC } from '@codesandbox/common/lib/utils/keycodes' ;
7+ import { isMenuClicked } from '@codesandbox/components' ;
68import { SandboxCard , SkeletonCard } from './SandboxCard' ;
79import { SandboxListItem , SkeletonListItem } from './SandboxListItem' ;
810
@@ -22,6 +24,8 @@ export const Sandbox = ({ sandbox, isTemplate = false, ...props }) => {
2224 alias : sandbox . alias ,
2325 } ) ;
2426
27+ /* Edit logic */
28+
2529 const onChange = ( event : React . ChangeEvent < HTMLInputElement > ) => {
2630 setNewTitle ( event . target . value ) ;
2731 } ;
@@ -57,13 +61,43 @@ export const Sandbox = ({ sandbox, isTemplate = false, ...props }) => {
5761 setTimeout ( ( ) => inputRef . current . focus ( ) ) ;
5862 } ;
5963
64+ /* Drag logic */
65+
66+ const [ dragging , setDragging ] = React . useState ( false ) ;
67+
68+ const onDragStart = ( ) => {
69+ setDragging ( true ) ;
70+ } ;
71+
72+ const onDragEnd = ( ) => {
73+ // delay by a frame so that click happens first
74+ window . requestAnimationFrame ( ( ) => setDragging ( false ) ) ;
75+ } ;
76+
77+ /* View logic */
78+ const location = useLocation ( ) ;
79+
80+ let viewMode : string ;
81+ if ( location . pathname . includes ( 'deleted' ) ) viewMode = 'list' ;
82+ else if ( location . pathname . includes ( 'start' ) ) viewMode = 'grid' ;
83+ else viewMode = dashboard . viewMode ;
84+
85+ const Component = viewMode === 'list' ? SandboxListItem : SandboxCard ;
86+
87+ /* Prevent opening sandbox while interacting */
88+ const onClick = event => {
89+ if ( edit || dragging || isMenuClicked ( event ) ) event . preventDefault ( ) ;
90+ } ;
91+
6092 const sandboxProps = {
6193 sandboxTitle,
62- newTitle,
6394 sandbox,
6495 isTemplate,
6596 url,
97+ onClick,
98+ // edit mode
6699 edit,
100+ newTitle,
67101 inputRef,
68102 onChange,
69103 onKeyDown,
@@ -72,17 +106,24 @@ export const Sandbox = ({ sandbox, isTemplate = false, ...props }) => {
72106 enterEditing,
73107 } ;
74108
75- const location = useLocation ( ) ;
76-
77- let viewMode ;
78- if ( location . pathname . includes ( 'deleted' ) ) viewMode = 'list' ;
79- else if ( location . pathname . includes ( 'start' ) ) viewMode = 'grid' ;
80- else viewMode = dashboard . viewMode ;
109+ const dragProps = {
110+ drag : true ,
111+ // boundaries beyond which dragging is constrained
112+ // setting it to 0 brings card back to its position
113+ dragConstraints : { top : 0 , bottom : 0 , left : 0 , right : 0 } ,
114+ // To allow drag dispite constraints, we can allow
115+ // movement outside constraints (it still springs back)
116+ dragElastic : 1 ,
117+ // event handlers
118+ onDragStart,
119+ onDragEnd,
120+ } ;
81121
82- if ( viewMode === 'list' ) {
83- return < SandboxListItem { ...sandboxProps } { ...props } /> ;
84- }
85- return < SandboxCard { ...sandboxProps } { ...props } /> ;
122+ return (
123+ < motion . div { ...dragProps } >
124+ < Component { ...sandboxProps } { ...props } />
125+ </ motion . div >
126+ ) ;
86127} ;
87128
88129export const SkeletonSandbox = props => {
0 commit comments