1 0
import React, { Component } from 'react'
2 0
import PropTypes from 'prop-types'
3 0
import cx from 'classnames'
4
import * as Rsg from 'react-styleguidist'
5 0
import { isCodeVueSfc } from 'vue-inbrowser-compiler-utils'
6 0
import { polyfill } from 'react-lifecycles-compat'
7 0
import SimpleEditor from 'react-simple-code-editor'
8 0
import { highlight as prismHighlight, languages } from 'prismjs'
9 0
import 'prismjs/components/prism-clike'
10 0
import 'prismjs/components/prism-markup'
11 0
import 'prismjs/components/prism-javascript'
12 0
import 'prismjs/components/prism-jsx'
13 0
import { space } from 'react-styleguidist/lib/client/styles/theme'
14 0
import prismTheme from 'react-styleguidist/lib/client/styles/prismTheme'
15 0
import Styled, { JssInjectedProps } from 'rsg-components/Styled'
16 0
import { useStyleGuideContext } from 'rsg-components/Context'
17 0
import getScript from '../../../loaders/utils/getScript'
18
import { SanitizedStyleguidistConfig } from '../../../types/StyleGuide'
19

20 0
const highlight = (lang: 'vsg' | 'html', jsxInExamples: boolean): ((code: string) => string) => {
21 1
	if (lang === 'vsg') {
22 0
		return code => {
23 1
			if (!code) {
24 0
				return ''
25
			}
26 0
			const scriptCode = getScript(code, jsxInExamples)
27 0
			const scriptCodeHighlighted = prismHighlight(
28
				scriptCode,
29 1
				languages[jsxInExamples ? 'jsx' : 'js'],
30
				lang
31
			)
32 1
			if (code.length === scriptCode.length) {
33 0
				return scriptCodeHighlighted
34
			}
35 0
			const templateCode = code.slice(scriptCode.length)
36 0
			return scriptCodeHighlighted + prismHighlight(templateCode, languages.html, lang)
37
		}
38
	} else {
39 0
		const langScheme = languages[lang]
40 0
		return code => prismHighlight(code, langScheme, lang)
41
	}
42
}
43

44 0
const styles = ({ fontFamily, fontSize, color, borderRadius }: Rsg.Theme) => ({
45
	root: {
46
		fontFamily: fontFamily.monospace,
47
		fontSize: fontSize.small,
48
		borderRadius,
49
		'& textarea': {
50
			isolate: false,
51
			transition: 'all ease-in-out .1s',
52
			// important to override inline styles in react-simple-code-editor
53
			border: `1px ${color.border} solid !important`,
54
			borderRadius
55
		},
56
		'& textarea:focus': {
57
			isolate: false,
58
			outline: 0,
59
			borderColor: `${color.link} !important`,
60
			boxShadow: [[0, 0, 0, 2, color.focus]]
61
		}
62
	},
63
	jssEditor: {
64
		background: color.codeBackground,
65
		...prismTheme({ color })
66
	}
67
})
68

69
export interface UnconfiguredEditorProps extends JssInjectedProps {
70
	code: string
71
	jssThemedEditor: boolean
72
	jsxInExamples: boolean
73
	onChange: (val: string) => void
74
	editorPadding?: number
75
}
76

77 1
export class UnconfiguredEditor extends Component<UnconfiguredEditorProps> {
78 0
	public static propTypes = {
79
		classes: PropTypes.objectOf(PropTypes.string.isRequired).isRequired,
80
		code: PropTypes.string.isRequired,
81
		jssThemedEditor: PropTypes.bool.isRequired,
82
		jsxInExamples: PropTypes.bool.isRequired,
83
		onChange: PropTypes.func.isRequired,
84
		editorPadding: PropTypes.number
85
	}
86

87 0
	public state = { code: this.props.code, prevCode: this.props.code }
88

89 0
	public static getDerivedStateFromProps(
90
		nextProps: UnconfiguredEditorProps,
91 0
		prevState: { code: string; prevCode: string }
92
	) {
93 0
		const { code } = nextProps
94 1
		if (prevState.prevCode !== code) {
95 0
			return {
96
				prevCode: code,
97
				code
98
			}
99
		}
100 0
		return null
101
	}
102

103 0
	public shouldComponentUpdate(
104
		nextProps: UnconfiguredEditorProps,
105 0
		nextState: { code: string; prevCode: string }
106
	) {
107 0
		return nextState.code !== this.state.code
108
	}
109

110 0
	public handleChange = (code: string) => {
111 0
		this.setState({ code })
112 0
		this.props.onChange(code)
113
	}
114

115 0
	public render() {
116 0
		const { root, jssEditor } = this.props.classes
117 0
		const isVueSFC = isCodeVueSfc(this.state.code)
118 0
		const { jssThemedEditor, jsxInExamples, editorPadding } = this.props
119 1
		const langClass = isVueSFC ? 'language-html' : 'language-jsx'
120 0
		return (
121
			<SimpleEditor
122 1
				className={cx(root, jssThemedEditor ? jssEditor : langClass, 'prism-editor')}
123
				value={this.state.code}
124
				onValueChange={this.handleChange}
125 1
				highlight={highlight(isVueSFC ? 'html' : 'vsg', jsxInExamples)}
126
				// Padding should be passed via a prop (not CSS) for a proper
127
				// cursor position calculation
128 1
				padding={editorPadding || space[2]}
129
				// to make sure the css styles for prism are taken into account
130 1
				preClassName={cx(!jssThemedEditor && langClass)}
131
			/>
132
		)
133
	}
134 0
}
135

136 0
const PEditor = polyfill(UnconfiguredEditor)
137

138
type EditorProps = Omit<UnconfiguredEditorProps, 'jssThemedEditor' | 'jsxInExamples'>
139

140 0
function Editor(props: EditorProps) {
141
	const {
142 0
		config: { jssThemedEditor, jsxInExamples }
143 0
	} = (useStyleGuideContext() as any) as { config: SanitizedStyleguidistConfig }
144 0
	return <PEditor {...props} jssThemedEditor={jssThemedEditor} jsxInExamples={jsxInExamples} />
145
}
146

147 0
export default Styled<EditorProps>(styles as any)(Editor)

Read our documentation on viewing source code .

Loading