react-code-view
Version:
Code view for React
148 lines (147 loc) • 6.2 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
var _excluded = ["dependencies", "editor", "theme", "editable", "transformOptions", "code", "copyButtonAs", "copyButtonProps", "renderToolbar", "renderExtraFooter", "onOpenEditor", "onCloseEditor", "onChange", "beforeCompile", "afterCompile"],
_excluded2 = ["classPrefix", "icon", "className", "buttonClassName", "showCodeButtonProps"];
/* eslint-disable @typescript-eslint/no-var-requires */
import classNames from 'classnames';
import CodeEditor from './CodeEditor';
import Preview from './Preview';
import canUseDOM from './utils/canUseDOM';
import evalCode from './utils/evalCode';
import CodeIcon from './icons/Code';
import { useEffect, useState, useCallback, createElement as _createElement } from 'react';
import { transform as transformCode } from 'sucrase';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
var React = require('react');
var ReactDOM = require('react-dom');
var defaultTransformOptions = {
transforms: ['jsx']
};
var Renderer = React.forwardRef(function (props, ref) {
var dependencies = props.dependencies,
_props$editor = props.editor,
editor = _props$editor === void 0 ? {} : _props$editor,
_props$theme = props.theme,
theme = _props$theme === void 0 ? 'light' : _props$theme,
_props$editable = props.editable,
isEditable = _props$editable === void 0 ? false : _props$editable,
_props$transformOptio = props.transformOptions,
transformOptions = _props$transformOptio === void 0 ? defaultTransformOptions : _props$transformOptio,
code = props.code,
copyButtonAs = props.copyButtonAs,
copyButtonProps = props.copyButtonProps,
renderToolbar = props.renderToolbar,
renderExtraFooter = props.renderExtraFooter,
onOpenEditor = props.onOpenEditor,
onCloseEditor = props.onCloseEditor,
onChange = props.onChange,
beforeCompile = props.beforeCompile,
afterCompile = props.afterCompile,
rest = _objectWithoutPropertiesLoose(props, _excluded);
var classPrefix = editor.classPrefix,
codeIcon = editor.icon,
editorClassName = editor.className,
buttonClassName = editor.buttonClassName,
showCodeButtonProps = editor.showCodeButtonProps,
editorProps = _objectWithoutPropertiesLoose(editor, _excluded2);
var _useState = useState(isEditable),
editable = _useState[0],
setEditable = _useState[1];
var _useState2 = useState(null),
errorMessage = _useState2[0],
setErrorMessage = _useState2[1];
var _useState3 = useState(null),
compiledReactNode = _useState3[0],
setCompiledReactNode = _useState3[1];
var handleExpandEditor = useCallback(function () {
setEditable(!editable);
if (editable) {
onCloseEditor === null || onCloseEditor === void 0 ? void 0 : onCloseEditor();
} else if (!editable) {
onOpenEditor === null || onOpenEditor === void 0 ? void 0 : onOpenEditor();
}
}, [editable, onCloseEditor, onOpenEditor]);
var handleError = useCallback(function (error) {
setErrorMessage(error.message);
}, []);
var prefix = function prefix(name) {
return classPrefix ? classPrefix + "-" + name : name;
};
var executeCode = useCallback(function (pendCode) {
if (pendCode === void 0) {
pendCode = code;
}
if (!canUseDOM) {
return;
}
var originalRender = ReactDOM.render;
// Redefine the render function, which will reset to the default value after `eval` is executed.
ReactDOM.render = function (element) {
setCompiledReactNode(element);
};
try {
var beforeCompileCode = (beforeCompile === null || beforeCompile === void 0 ? void 0 : beforeCompile(pendCode)) || pendCode;
if (beforeCompileCode) {
var _transformCode = transformCode(beforeCompileCode, transformOptions),
compiledCode = _transformCode.code;
evalCode((afterCompile === null || afterCompile === void 0 ? void 0 : afterCompile(compiledCode)) || compiledCode, _extends({
React: React,
ReactDOM: ReactDOM
}, dependencies));
}
} catch (err) {
console.warn(err);
} finally {
// Reset the render function to the original value.
ReactDOM.render = originalRender;
}
}, [code, dependencies, beforeCompile, transformOptions, afterCompile]);
useEffect(function () {
executeCode(code);
}, [code, executeCode]);
var handleCodeChange = useCallback(function (code) {
onChange === null || onChange === void 0 ? void 0 : onChange(code);
executeCode(code);
setErrorMessage(null);
}, [executeCode, onChange]);
var toggleButtonProps = _extends({
role: 'switch',
'aria-checked': editable,
'aria-label': 'Show the full source',
className: buttonClassName,
onClick: handleExpandEditor
}, showCodeButtonProps);
var showCodeButton = /*#__PURE__*/_jsx("button", _extends({}, toggleButtonProps, {
children: typeof codeIcon !== 'undefined' ? codeIcon : /*#__PURE__*/_jsx(CodeIcon, {
className: classNames(prefix('icon'), prefix('icon-code'))
})
}));
var showCodeEditor = editable && code;
var hasError = !!errorMessage;
return /*#__PURE__*/_jsxs("div", _extends({
className: "rcv-container"
}, rest, {
ref: ref,
children: [/*#__PURE__*/_jsx(Preview, {
hasError: hasError,
errorMessage: errorMessage,
onError: handleError,
children: compiledReactNode
}), /*#__PURE__*/_jsx("div", {
className: "rcv-toolbar",
children: renderToolbar ? renderToolbar(showCodeButton, toggleButtonProps) : showCodeButton
}), showCodeEditor && /*#__PURE__*/_createElement(CodeEditor, _extends({}, editorProps, {
key: "jsx",
copyButtonAs: copyButtonAs,
copyButtonProps: copyButtonProps,
onChange: handleCodeChange,
className: classNames(editorClassName, 'rcv-editor'),
editorConfig: {
lineNumbers: true,
theme: "base16-" + theme
},
code: code
})), renderExtraFooter === null || renderExtraFooter === void 0 ? void 0 : renderExtraFooter()]
}));
});
export default Renderer;