1
- import React , { useCallback } from 'react' ;
1
+ import React , { useCallback , useEffect , useRef } from 'react' ;
2
2
import { useDispatch , useSelector } from 'react-redux' ;
3
- import Split from 'react- split-grid' ;
3
+ import Split from 'split-grid' ;
4
4
5
5
import Editor from './Editor' ;
6
6
import Header from './Header' ;
@@ -12,103 +12,91 @@ import * as actions from './actions';
12
12
13
13
import styles from './Playground.module.css' ;
14
14
15
- const NoOutput : React . SFC = ( ) => (
16
- < div className = { styles . editor } > < Editor /> </ div >
17
- ) ;
18
-
19
- const PlainRows : React . SFC = ( ) => (
20
- < div className = { styles . plainRows } >
21
- < div className = { styles . editor } > < Editor /> </ div >
22
- < div className = { styles . output } > < Output /> </ div >
23
- </ div >
24
- ) ;
25
-
26
- const PlainColumns : React . SFC = ( ) => (
27
- < div className = { styles . plainColumns } >
28
- < div className = { styles . editor } > < Editor /> </ div >
29
- < div className = { styles . output } > < Output /> </ div >
30
- </ div >
31
- ) ;
32
-
33
- interface SplitProps {
34
- resizeComplete : ( ) => void ;
15
+ const TRACK_OPTION_NAME = {
16
+ [ Orientation . Horizontal ] : 'rowGutters' ,
17
+ [ Orientation . Vertical ] : 'columnGutters' ,
35
18
}
36
19
37
- const SplitRows : React . SFC < SplitProps > = ( { resizeComplete } ) => (
38
- < Split
39
- minSize = { 100 }
40
- onDragEnd = { resizeComplete }
41
- render = { ( {
42
- getGridProps,
43
- getGutterProps,
44
- } ) => (
45
- < div className = { styles . splitRows } { ...getGridProps ( ) } >
46
- < div className = { styles . editor } > < Editor /> </ div >
47
- < div className = { styles . splitRowsGutter } { ...getGutterProps ( 'row' , 1 ) } >
48
- < span className = { styles . splitRowsGutterHandle } > ⣿</ span >
49
- </ div >
50
- < div className = { styles . output } > < Output /> </ div >
51
- </ div >
52
- ) } />
53
- )
54
-
55
- const SplitColumns : React . SFC < SplitProps > = ( { resizeComplete } ) => (
56
- < Split
57
- minSize = { 100 }
58
- onDragEnd = { resizeComplete }
59
- render = { ( {
60
- getGridProps,
61
- getGutterProps,
62
- } ) => (
63
- < div className = { styles . splitColumns } { ...getGridProps ( ) } >
64
- < div className = { styles . editor } > < Editor /> </ div >
65
- < div className = { styles . splitColumnsGutter } { ...getGutterProps ( 'column' , 1 ) } > ⣿</ div >
66
- < div className = { styles . output } > < Output /> </ div >
67
- </ div >
68
- ) } />
69
- )
20
+ const FOCUSED_GRID_STYLE = {
21
+ [ Orientation . Horizontal ] : styles . resizeableAreaRowOutputFocused ,
22
+ [ Orientation . Vertical ] : styles . resizeableAreaColumnOutputFocused ,
23
+ }
70
24
71
- const ORIENTATION_PLAIN_MAP = {
72
- [ Orientation . Horizontal ] : PlainRows ,
73
- [ Orientation . Vertical ] : PlainColumns ,
25
+ const UNFOCUSED_GRID_STYLE = {
26
+ [ Orientation . Horizontal ] : styles . resizeableAreaRowOutputUnfocused ,
27
+ [ Orientation . Vertical ] : styles . resizeableAreaColumnOutputUnfocused ,
74
28
}
75
29
76
- const ORIENTATION_SPLIT_MAP = {
77
- [ Orientation . Horizontal ] : SplitRows ,
78
- [ Orientation . Vertical ] : SplitColumns ,
30
+ const HANDLE_STYLES = {
31
+ [ Orientation . Horizontal ] : [ styles . splitRowsGutter , styles . splitRowsGutterHandle ] ,
32
+ [ Orientation . Vertical ] : [ styles . splitColumnsGutter , '' ] ,
79
33
}
80
34
81
- const Playground : React . SFC = ( ) => {
82
- const showNotifications = useSelector ( selectors . anyNotificationsToShowSelector ) ;
35
+ // We drop down to lower-level split-grid code and use some hooks
36
+ // because we want to reduce the number of times that the Editor
37
+ // component is remounted. Each time it's remounted, we see a flicker and
38
+ // lose state (like undo history).
39
+ const ResizableArea : React . SFC = ( ) => {
83
40
const somethingToShow = useSelector ( selectors . getSomethingToShow ) ;
84
41
const isFocused = useSelector ( selectors . isOutputFocused ) ;
85
42
const orientation = useSelector ( selectors . orientation ) ;
86
43
87
44
const dispatch = useDispatch ( ) ;
88
45
const resizeComplete = useCallback ( ( ) => dispatch ( actions . splitRatioChanged ( ) ) , [ dispatch ] ) ;
89
46
90
- let Foo ;
91
- if ( ! somethingToShow ) {
92
- Foo = NoOutput ;
93
- } else {
94
- if ( isFocused ) {
95
- Foo = ORIENTATION_SPLIT_MAP [ orientation ] ;
96
- } else {
97
- Foo = ORIENTATION_PLAIN_MAP [ orientation ] ;
98
- }
99
- }
47
+ const grid = useRef ( null ) ;
48
+ const dragHandle = useRef ( null ) ;
49
+
50
+ // Reset styles left on the grid from split-grid when we change orientation or focus.
51
+ useEffect ( ( ) => {
52
+ grid . current . style [ 'grid-template-columns' ] = null ;
53
+ grid . current . style [ 'grid-template-rows' ] = null ;
54
+
55
+ resizeComplete ( ) ;
56
+ } , [ orientation , isFocused , resizeComplete ] )
57
+
58
+ useEffect ( ( ) => {
59
+ const split = Split ( {
60
+ minSize : 100 ,
61
+ [ TRACK_OPTION_NAME [ orientation ] ] : [ {
62
+ track : 1 ,
63
+ element : dragHandle . current ,
64
+ } ] ,
65
+ onDragEnd : resizeComplete ,
66
+ } ) ;
67
+
68
+ return ( ) => split . destroy ( ) ;
69
+ } , [ orientation , isFocused , somethingToShow , resizeComplete ] )
70
+
71
+ const gridStyles = isFocused ? FOCUSED_GRID_STYLE : UNFOCUSED_GRID_STYLE ;
72
+ const gridStyle = gridStyles [ orientation ] ;
73
+ const [ handleOuterStyle , handleInnerStyle ] = HANDLE_STYLES [ orientation ] ;
74
+
75
+ return (
76
+ < div ref = { grid } className = { gridStyle } >
77
+ < div className = { styles . editor } > < Editor /> </ div >
78
+ { isFocused &&
79
+ < div ref = { dragHandle } className = { handleOuterStyle } >
80
+ < span className = { handleInnerStyle } > ⣿</ span >
81
+ </ div >
82
+ }
83
+ { somethingToShow && < div className = { styles . output } > < Output /> </ div > }
84
+ </ div >
85
+ ) ;
86
+ } ;
87
+
88
+ const Playground : React . SFC = ( ) => {
89
+ const showNotifications = useSelector ( selectors . anyNotificationsToShowSelector ) ;
100
90
101
91
return (
102
92
< >
103
93
< div className = { styles . container } >
104
- < div >
105
- < Header />
106
- </ div >
107
- < Foo resizeComplete = { resizeComplete } />
94
+ < Header />
95
+ < ResizableArea />
108
96
</ div >
109
97
{ showNotifications && < Notifications /> }
110
98
</ >
111
99
) ;
112
- } ;
100
+ }
113
101
114
102
export default Playground ;
0 commit comments