11/** @jsx jsx */
22import { jsx } from 'theme-ui'
3- import { useState } from 'react'
3+ import React from 'react'
44import { useConfig } from 'docz'
55import { LiveProvider , LiveError , LivePreview , LiveEditor } from 'react-live'
66import { Resizable } from 're-resizable'
77import copy from 'copy-text-to-clipboard'
8+ import ReactResizeDetector from 'react-resize-detector'
89
10+ import { IframeWrapper } from './IframeWrapper'
911import { usePrismTheme } from '~utils/theme'
1012import * as styles from './styles'
1113import * as Icons from '../Icons'
1214
15+ const getResizableProps = ( width , setWidth ) => ( {
16+ minWidth : 260 ,
17+ maxWidth : '100%' ,
18+ size : {
19+ width : width ,
20+ height : 'auto' ,
21+ } ,
22+ style : {
23+ margin : 0 ,
24+ marginRight : 'auto' ,
25+ } ,
26+ enable : {
27+ top : false ,
28+ right : true ,
29+ bottom : false ,
30+ left : false ,
31+ topRight : false ,
32+ bottomRight : false ,
33+ bottomLeft : false ,
34+ topLeft : false ,
35+ } ,
36+ onResizeStop : ( e , direction , ref ) => {
37+ setWidth ( ref . style . width )
38+ } ,
39+ } )
40+
1341const transformCode = code => {
1442 if ( code . startsWith ( '()' ) || code . startsWith ( 'class' ) ) return code
1543 return `<React.Fragment>${ code } </React.Fragment>`
1644}
1745
18- export const Playground = ( { code, scope, language } ) => {
46+ export const Playground = ( { code, scope, language, useScoping = false } ) => {
1947 const {
20- themeConfig : { showPlaygroundEditor, showLiveError, showLivePreview } ,
48+ themeConfig : {
49+ showPlaygroundEditor,
50+ showLiveError,
51+ showLivePreview,
52+ useScopingInPlayground,
53+ } ,
2154 } = useConfig ( )
55+
56+ const [ previewHeight , setPreviewHeight ] = React . useState ( )
57+ const [ editorHeight , setEditorHeight ] = React . useState ( )
58+ const Wrapper = React . useCallback (
59+ useScoping || useScopingInPlayground
60+ ? props => < IframeWrapper { ...props } > { props . children } </ IframeWrapper >
61+ : props => (
62+ < div sx = { styles . previewInner ( showingCode ) } > { props . children } </ div >
63+ ) ,
64+ [ useScoping ]
65+ )
66+
2267 // Makes sure scope is only given on mount to avoid infinite re-render on hot reloads
23- const [ scopeOnMount ] = useState ( scope )
68+ const [ scopeOnMount ] = React . useState ( scope )
2469 const theme = usePrismTheme ( )
25- const [ showingCode , setShowingCode ] = useState ( ( ) => showPlaygroundEditor )
26- const [ width , setWidth ] = useState ( ( ) => '100%' )
70+ const [ showingCode , setShowingCode ] = React . useState ( showPlaygroundEditor )
71+ const [ width , setWidth ] = React . useState ( '100%' )
72+ const resizableProps = getResizableProps ( width , setWidth )
2773
2874 const copyCode = ( ) => copy ( code )
29-
3075 const toggleCode = ( ) => setShowingCode ( s => ! s )
3176
32- const resizableProps = {
33- minWidth : 260 ,
34- maxWidth : '100%' ,
35- size : {
36- width,
37- height : 'auto' ,
38- } ,
39- style : {
40- margin : 0 ,
41- marginRight : 'auto' ,
42- } ,
43- enable : {
44- top : false ,
45- right : true ,
46- bottom : false ,
47- left : false ,
48- topRight : false ,
49- bottomRight : false ,
50- bottomLeft : false ,
51- topLeft : false ,
52- } ,
53- onResizeStop : ( e , direction , ref ) => {
54- setWidth ( ref . style . width )
55- } ,
56- }
57-
5877 return (
5978 < Resizable { ...resizableProps } data-testid = "playground" >
6079 < LiveProvider
@@ -65,11 +84,17 @@ export const Playground = ({ code, scope, language }) => {
6584 theme = { theme }
6685 >
6786 < div sx = { styles . previewWrapper } >
68- < div sx = { styles . previewInner ( showingCode ) } >
87+ < Wrapper height = { previewHeight } >
6988 { showLivePreview && (
70- < LivePreview sx = { styles . preview } data-testid = "live-preview" />
89+ < LivePreview style = { styles . preview } data-testid = "live-preview" />
7190 ) }
72- </ div >
91+ < ReactResizeDetector
92+ handleHeight
93+ onResize = { ( width , height ) => {
94+ setPreviewHeight ( height )
95+ } }
96+ />
97+ </ Wrapper >
7398 < div sx = { styles . buttons } >
7499 < button sx = { styles . button } onClick = { copyCode } >
75100 < Icons . Clipboard size = { 12 } />
@@ -79,14 +104,22 @@ export const Playground = ({ code, scope, language }) => {
79104 </ button >
80105 </ div >
81106 </ div >
107+ { showingCode && (
108+ < Wrapper height = { editorHeight } >
109+ < div style = { styles . editor ( theme ) } >
110+ < LiveEditor data-testid = "live-editor" />
111+ </ div >
112+ < ReactResizeDetector
113+ handleHeight
114+ onResize = { ( width , height ) => {
115+ setEditorHeight ( height )
116+ } }
117+ />
118+ </ Wrapper >
119+ ) }
82120 { showLiveError && (
83121 < LiveError sx = { styles . error } data-testid = "live-error" />
84122 ) }
85- { showingCode && (
86- < div sx = { styles . editor ( theme ) } >
87- < LiveEditor data-testid = "live-editor" />
88- </ div >
89- ) }
90123 </ LiveProvider >
91124 </ Resizable >
92125 )
0 commit comments