/
CodeEditor.js
139 lines (129 loc) · 3.03 KB
/
CodeEditor.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
127
128
129
130
131
132
133
134
135
136
137
138
139
import React, { useState, useEffect } from 'react'
import styled from 'styled-components'
import { LiveProvider, LiveEditor, LiveError, LivePreview } from 'react-live'
import { transform } from 'babel-standalone'
import theme from 'prism-react-renderer/themes/oceanicNext'
const Wrapper = styled.div`
margin: 0 auto 2rem;
`
const Container = styled.div`
position: relative;
@media screen and (min-width: ${props => props.theme.responsive.small}) {
display: flex;
flex-flow: row wrap;
}
h3 {
font-weight: default;
}
`
const Preview = styled(LivePreview)`
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
border: 2px solid ${props => props.theme.colors.base};
background: white;
position: relative;
padding: 1.5rem;
display: block;
height: auto;
flex-basis: 50%;
white-space: normal;
overflow: hidden;
@media screen and (min-width: ${props => props.theme.responsive.small}) {
flex: 0 0 50%;
min-height: 10rem;
border-top-right-radius: 3px;
border-bottom-left-radius: 0;
}
`
const Editor = styled(LiveEditor)`
padding: 1rem !important;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
font-size: 1.05em;
line-height: 1.2em;
textarea {
padding: 1.5rem !important;
background: ${props => props.theme.colors.base} !important;
}
textarea:focus {
outline: none;
}
::-webkit-scrollbar {
display: none;
}
@media screen and (min-width: ${props => props.theme.responsive.small}) {
flex: 0 0 50%;
border-top-right-radius: 0;
border-bottom-left-radius: 3px;
}
`
const Error = styled(LiveError)`
background: #f68987;
padding: 1rem;
width: 100%;
overflow: scroll;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
`
const Label = styled.span`
color: white;
border-bottom-right-radius: 3px;
display: none;
position: absolute;
font-size: 0.95em;
bottom: 0;
right: 0;
padding: 0.5em 0.5em 0.5em 1.25em;
border-top-left-radius: 3px;
background: ${props => props.theme.colors.base};
&::before {
content: '';
position: absolute;
left: 0.35em;
top: 0.7em;
width: 8px;
height: 8px;
border-radius: 50%;
background: ${props => props.theme.colors.highlight};
animation: blinker 2s linear infinite;
}
@keyframes blinker {
50% {
opacity: 0;
}
}
@media screen and (min-width: ${props => props.theme.responsive.small}) {
display: inline-block;
}
`
const scope = { styled, useState, useEffect }
const transformCode = code => {
try {
code = transform(code, {
presets: ['react', 'stage-0'],
}).code
return code
} catch (e) {
console.log(e)
return code
}
}
const CodeEditor = ({ children, ...props }) => (
<Wrapper>
<LiveProvider
noInline
code={children}
scope={scope}
transformCode={transformCode}
theme={theme}
>
<Container>
<Editor />
<Preview />
<Label>Demo</Label>
</Container>
<Error />
</LiveProvider>
</Wrapper>
)
export default CodeEditor