1- import React , { useCallback } from 'react' ;
1+ import React , { useCallback , useEffect , useRef } from 'react' ;
22import { useDispatch , useSelector } from 'react-redux' ;
3- import Split from 'react- split-grid' ;
3+ import Split from 'split-grid' ;
44
55import Editor from './Editor' ;
66import Header from './Header' ;
@@ -12,103 +12,91 @@ import * as actions from './actions';
1212
1313import styles from './Playground.module.css' ;
1414
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' ,
3518}
3619
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+ }
7024
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 ,
7428}
7529
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 , '' ] ,
7933}
8034
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 = ( ) => {
8340 const somethingToShow = useSelector ( selectors . getSomethingToShow ) ;
8441 const isFocused = useSelector ( selectors . isOutputFocused ) ;
8542 const orientation = useSelector ( selectors . orientation ) ;
8643
8744 const dispatch = useDispatch ( ) ;
8845 const resizeComplete = useCallback ( ( ) => dispatch ( actions . splitRatioChanged ( ) ) , [ dispatch ] ) ;
8946
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 ) ;
10090
10191 return (
10292 < >
10393 < div className = { styles . container } >
104- < div >
105- < Header />
106- </ div >
107- < Foo resizeComplete = { resizeComplete } />
94+ < Header />
95+ < ResizableArea />
10896 </ div >
10997 { showNotifications && < Notifications /> }
11098 </ >
11199 ) ;
112- } ;
100+ }
113101
114102export default Playground ;
0 commit comments