mirror of
https://github.com/zhigang1992/react.git
synced 2026-02-05 22:47:21 +08:00
fix(playground): fix arrow icon does not work correctly on webkit
This commit is contained in:
128
lib/components/playground/editor.tsx
Normal file
128
lib/components/playground/editor.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import React, { useState } from 'react'
|
||||
import { LiveEditor } from 'react-live'
|
||||
import { useConfigs } from 'lib/config-context'
|
||||
import { useTheme, useToasts, Row, Col, Utils } from 'components'
|
||||
import CopyIcon from '@zeit-ui/react-icons/copy'
|
||||
import RightIcon from '@zeit-ui/react-icons/chevronRight'
|
||||
const { useClipboard } = Utils
|
||||
|
||||
interface Props {
|
||||
code: string
|
||||
}
|
||||
|
||||
const Editor: React.FC<Props> = ({ code }) => {
|
||||
const theme = useTheme()
|
||||
const { copy } = useClipboard()
|
||||
const { isChinese } = useConfigs()
|
||||
const [visible, setVisible] = useState(false)
|
||||
const [, setToast] = useToasts()
|
||||
const clickHandler = (event: React.MouseEvent) => {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
setVisible(!visible)
|
||||
}
|
||||
|
||||
const copyHandler = (event: React.MouseEvent) => {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
copy(code)
|
||||
setToast({ text: isChinese ? '代码已拷贝至剪切板。' : 'code copied.' })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="editor">
|
||||
<details open={visible}>
|
||||
<summary onClick={clickHandler}>
|
||||
<Row justify="space-between" align="middle" style={{ height: '100%', width: '100%' }}>
|
||||
<Col className="action">
|
||||
<span className="arrow"><RightIcon size={16} /></span>
|
||||
<span>{isChinese ? '编辑代码' : 'Code Editor'}</span>
|
||||
</Col>
|
||||
<Col className="action">
|
||||
{visible && (
|
||||
<span className="copy" onClick={copyHandler} title={isChinese ? '拷贝代码' : 'Copy Code'}>
|
||||
<CopyIcon size={18} />
|
||||
</span>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</summary>
|
||||
<div className="area"><LiveEditor /></div>
|
||||
</details>
|
||||
|
||||
<style jsx>{`
|
||||
.editor {
|
||||
border-bottom-left-radius: ${theme.layout.radius};
|
||||
border-bottom-right-radius: ${theme.layout.radius};
|
||||
}
|
||||
|
||||
details {
|
||||
transition: all 0.2s ease;
|
||||
overflow: hidden;
|
||||
border-bottom-left-radius: ${theme.layout.radius};
|
||||
border-bottom-right-radius: ${theme.layout.radius};
|
||||
}
|
||||
|
||||
summary {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 ${theme.layout.gap};
|
||||
border-top: 1px solid ${theme.palette.accents_2};
|
||||
color: ${theme.palette.accents_5};
|
||||
height: 2.875rem;
|
||||
list-style: none;
|
||||
user-select: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
summary :global(svg) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
summary :global(.action) {
|
||||
width: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
||||
.area {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
white-space: pre;
|
||||
font-family: ${theme.font.mono};
|
||||
color: ${theme.palette.foreground};
|
||||
background-color: ${theme.palette.background};
|
||||
font-size: 1em;
|
||||
overflow: hidden;
|
||||
border-top: 1px solid ${theme.palette.accents_2};
|
||||
padding: ${theme.layout.gapHalf};
|
||||
}
|
||||
|
||||
.arrow {
|
||||
transition: all .2s ease;
|
||||
transform: rotate(${visible ? 90 : 0}deg);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
.copy {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: ${theme.palette.accents_4};
|
||||
transition: color .2s ease;
|
||||
}
|
||||
|
||||
.copy:hover {
|
||||
color: ${theme.palette.accents_6};
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Editor
|
||||
@@ -1,12 +1,10 @@
|
||||
import React, { useState } from 'react'
|
||||
import { LivePreview, LiveProvider, LiveEditor, LiveError } from 'react-live'
|
||||
import React from 'react'
|
||||
import { useTheme } from 'components'
|
||||
import withDefaults from 'components/utils/with-defaults'
|
||||
import useClipboard from 'components/utils/use-clipboard'
|
||||
import { useTheme, useToasts } from 'components'
|
||||
import { LivePreview, LiveProvider, LiveError } from 'react-live'
|
||||
import { useConfigs } from 'lib/config-context'
|
||||
import makeCodeTheme from './code-theme'
|
||||
import RightIcon from '@zeit-ui/react-icons/chevronRight'
|
||||
import CopyIcon from '@zeit-ui/react-icons/copy'
|
||||
import Editor from './editor'
|
||||
import Title from './title'
|
||||
|
||||
interface Props {
|
||||
@@ -26,126 +24,12 @@ const defaultProps = {
|
||||
|
||||
export type PlaygroundProps = Props & typeof defaultProps
|
||||
|
||||
const editor = (code: string, copy: Function, isChinese: boolean) => {
|
||||
const theme = useTheme()
|
||||
const [visible, setVisible] = useState(false)
|
||||
|
||||
const [, setToast] = useToasts()
|
||||
const clickHandler = (event: React.MouseEvent) => {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
setVisible(!visible)
|
||||
}
|
||||
|
||||
const copyHandler = (event: React.MouseEvent) => {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
copy(code)
|
||||
setToast({ text: isChinese ? '代码已拷贝至剪切板。' : 'code copied.' })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="editor">
|
||||
<details open={visible}>
|
||||
<summary onClick={clickHandler}>
|
||||
<div>
|
||||
<span className="right-icon">
|
||||
<RightIcon size={16} />
|
||||
</span>
|
||||
<span>{isChinese ? '编辑代码' : 'Code Editor'}</span>
|
||||
</div>
|
||||
<div>
|
||||
{visible && (
|
||||
<span className="copy" onClick={copyHandler} title={isChinese ? '拷贝代码' : 'Copy Code'}>
|
||||
<CopyIcon size={18} />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</summary>
|
||||
<div className="area">
|
||||
<LiveEditor />
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<style jsx>{`
|
||||
.editor {
|
||||
border-bottom-left-radius: ${theme.layout.radius};
|
||||
border-bottom-right-radius: ${theme.layout.radius};
|
||||
}
|
||||
|
||||
details {
|
||||
transition: all 0.2s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 ${theme.layout.gapHalf};
|
||||
border-top: 1px solid ${theme.palette.accents_2};
|
||||
color: ${theme.palette.accents_5};
|
||||
height: 2.875rem;
|
||||
list-style: none;
|
||||
user-select: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
summary > div {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
summary :global(svg) {
|
||||
margin: 0 ${theme.layout.gapHalf};
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.area {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
white-space: pre;
|
||||
font-family: ${theme.font.mono};
|
||||
color: ${theme.palette.foreground};
|
||||
background-color: ${theme.palette.background};
|
||||
font-size: 1em;
|
||||
overflow: hidden;
|
||||
border-top: 1px solid ${theme.palette.accents_2};
|
||||
padding: ${theme.layout.gapHalf};
|
||||
}
|
||||
|
||||
.right-icon {
|
||||
transition: all .2s ease;
|
||||
transform: rotate(${visible ? 90 : 0}deg);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.copy {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: ${theme.palette.accents_4};
|
||||
transition: color .2s ease;
|
||||
}
|
||||
|
||||
.copy:hover {
|
||||
color: ${theme.palette.accents_6};
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Playground: React.FC<PlaygroundProps> = React.memo(({
|
||||
title: inputTitle, code: inputCode, desc, scope,
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const { isChinese } = useConfigs()
|
||||
const codeTheme = makeCodeTheme(theme)
|
||||
const { copy } = useClipboard()
|
||||
const code = inputCode.trim()
|
||||
const title = inputTitle || (isChinese ? '基础的' : 'Default')
|
||||
|
||||
@@ -158,24 +42,24 @@ const Playground: React.FC<PlaygroundProps> = React.memo(({
|
||||
<LivePreview />
|
||||
<LiveError />
|
||||
</div>
|
||||
{editor(code, copy, !!isChinese)}
|
||||
<Editor code={code} />
|
||||
</LiveProvider>
|
||||
|
||||
<style jsx>{`
|
||||
.playground {
|
||||
width: 100%;
|
||||
border-radius: ${theme.layout.radius};
|
||||
border: 1px solid ${theme.palette.accents_2};
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
padding: ${theme.layout.pageMargin};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
`}</style>
|
||||
.playground {
|
||||
width: 100%;
|
||||
border-radius: ${theme.layout.radius};
|
||||
border: 1px solid ${theme.palette.accents_2};
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
padding: ${theme.layout.pageMargin};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user