This repository has been archived by the owner on Jan 24, 2025. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
Copy pathindex.js
126 lines (118 loc) · 3.6 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/** @jsx jsx */
import { jsx } from 'theme-ui'
import React from 'react'
import { useConfig } from 'docz'
import { LiveProvider, LiveError, LivePreview, LiveEditor } from 'react-live'
import { Resizable } from 're-resizable'
import copy from 'copy-text-to-clipboard'
import ReactResizeDetector from 'react-resize-detector'
import { IframeWrapper } from './IframeWrapper'
import { usePrismTheme } from '~utils/theme'
import * as styles from './styles'
import * as Icons from '../Icons'
const getResizableProps = (width, setWidth) => ({
minWidth: 260,
maxWidth: '100%',
size: {
width: width,
height: 'auto',
},
style: {
margin: 0,
marginRight: 'auto',
},
enable: {
top: false,
right: true,
bottom: false,
left: false,
topRight: false,
bottomRight: false,
bottomLeft: false,
topLeft: false,
},
onResizeStop: (e, direction, ref) => {
setWidth(ref.style.width)
},
})
const transformCode = code => {
if (code.startsWith('()') || code.startsWith('class')) return code
return `<React.Fragment>${code}</React.Fragment>`
}
export const Playground = ({ code, scope, language, useScoping = false }) => {
const {
themeConfig: {
showPlaygroundEditor,
showLiveError,
showLivePreview,
useScopingInPlayground,
},
} = useConfig()
const [previewHeight, setPreviewHeight] = React.useState()
const [editorHeight, setEditorHeight] = React.useState()
const Wrapper = React.useCallback(
useScoping || useScopingInPlayground
? props => <IframeWrapper {...props}>{props.children}</IframeWrapper>
: props => (
<div sx={styles.previewInner(showingCode)}>{props.children}</div>
),
[useScoping]
)
// Makes sure scope is only given on mount to avoid infinite re-render on hot reloads
const [scopeOnMount] = React.useState(scope)
const theme = usePrismTheme()
const [showingCode, setShowingCode] = React.useState(showPlaygroundEditor)
const [width, setWidth] = React.useState('100%')
const resizableProps = getResizableProps(width, setWidth)
const copyCode = () => copy(code)
const toggleCode = () => setShowingCode(s => !s)
return (
<Resizable {...resizableProps} data-testid="playground">
<LiveProvider
code={code}
scope={scopeOnMount}
transformCode={transformCode}
language={language}
theme={theme}
>
<div sx={styles.previewWrapper}>
<Wrapper height={previewHeight}>
{showLivePreview && (
<LivePreview style={styles.preview} data-testid="live-preview" />
)}
<ReactResizeDetector
handleHeight
onResize={({ height }) => {
setPreviewHeight(height)
}}
/>
</Wrapper>
<div sx={styles.buttons}>
<button sx={styles.button} onClick={copyCode}>
<Icons.Clipboard size={12} />
</button>
<button sx={styles.button} onClick={toggleCode}>
<Icons.Code size={12} />
</button>
</div>
</div>
{showingCode && (
<Wrapper height={editorHeight}>
<div style={styles.editor(theme)}>
<LiveEditor data-testid="live-editor" />
</div>
<ReactResizeDetector
handleHeight
onResize={({ height }) => {
setEditorHeight(height)
}}
/>
</Wrapper>
)}
{showLiveError && (
<LiveError sx={styles.error} data-testid="live-error" />
)}
</LiveProvider>
</Resizable>
)
}