UNPKG

@uiw/react-markdown-editor

Version:

A markdown editor with preview, implemented with React.js and TypeScript.

163 lines 6.51 kB
import _extends from "@babel/runtime/helpers/extends"; import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose"; var _excluded = ["prefixCls", "className", "onChange", "toolbars", "toolbarsMode", "toolbarsFilter", "visible", "renderPreview", "visibleEditor", "hideToolbar", "toolbarBottom", "enableScroll", "previewProps", "extensions", "previewWidth", "reExtensions"]; import React, { useState, useRef, useImperativeHandle, Fragment, useEffect, useCallback } from 'react'; import { markdown, markdownLanguage } from '@codemirror/lang-markdown'; import { languages } from '@codemirror/language-data'; import { EditorView } from '@codemirror/view'; import * as events from '@uiw/codemirror-extensions-events'; import CodeMirror from '@uiw/react-codemirror'; import MarkdownPreview from '@uiw/react-markdown-preview'; import ToolBar from './components/ToolBar'; import { getCommands, getModeCommands } from './commands'; import { defaultTheme } from './theme'; import "./index.css"; import { jsx as _jsx } from "react/jsx-runtime"; import { jsxs as _jsxs } from "react/jsx-runtime"; export * from './theme'; export * from './commands'; export * from '@uiw/react-markdown-preview'; export var scrollerStyle = EditorView.theme({ '&.cm-editor, & .cm-scroller': { borderBottomRightRadius: '3px', borderBottomLeftRadius: '3px' } }); var MarkdownEditor = /*#__PURE__*/React.forwardRef(MarkdownEditorInternal); MarkdownEditor.Markdown = MarkdownPreview; export default MarkdownEditor; function MarkdownEditorInternal(props, ref) { var { prefixCls = 'md-editor', className, onChange, toolbars = getCommands(), toolbarsMode = getModeCommands(), toolbarsFilter, visible = true, renderPreview, visibleEditor = true, hideToolbar = true, toolbarBottom = false, enableScroll = true, previewProps = {}, extensions = [], previewWidth = '50%', reExtensions } = props, codemirrorProps = _objectWithoutPropertiesLoose(props, _excluded); var [value, setValue] = useState(props.value || ''); var codeMirror = useRef(null); var container = useRef(null); var containerEditor = useRef(null); var preview = useRef(null); var active = useRef('editor'); useImperativeHandle(ref, () => ({ editor: codeMirror, preview: preview }), [codeMirror]); var toolBarProps = { preview: preview, editor: codeMirror, container: container, containerEditor: containerEditor, editorProps: _extends({}, props, { previewWidth }) }; var height = typeof codemirrorProps.height === 'number' ? codemirrorProps.height + "px" : codemirrorProps.height; var previewScrollHandle = useCallback(event => { if (!enableScroll) return; var target = event.target; var percent = target.scrollTop / target.scrollHeight; if (active.current === 'editor' && preview.current) { var _preview$current; var previewHeihgt = ((_preview$current = preview.current) == null ? void 0 : _preview$current.scrollHeight) || 0; preview.current.scrollTop = previewHeihgt * percent; } else if (codeMirror.current && codeMirror.current.view) { var editorScrollDom = codeMirror.current.view.scrollDOM; var editorScrollHeihgt = codeMirror.current.view.scrollDOM.scrollHeight || 0; editorScrollDom.scrollTop = editorScrollHeihgt * percent; } }, [enableScroll]); var mouseoverHandle = () => active.current = 'preview'; var mouseleaveHandle = () => active.current = 'editor'; useEffect(() => { var $preview = preview.current; if ($preview && enableScroll) { $preview.addEventListener('mouseover', mouseoverHandle, false); $preview.addEventListener('mouseleave', mouseleaveHandle, false); $preview.addEventListener('scroll', previewScrollHandle, false); } return () => { if ($preview && enableScroll) { $preview.removeEventListener('mouseover', mouseoverHandle); $preview.removeEventListener('mouseleave', mouseoverHandle); $preview.addEventListener('mouseleave', previewScrollHandle, false); } }; }, [preview, enableScroll, previewScrollHandle]); var scrollExtensions = events.scroll({ scroll: previewScrollHandle }); var extensionsData = reExtensions ? reExtensions : [markdown({ base: markdownLanguage, codeLanguages: languages }), scrollerStyle, ...extensions]; if (enableScroll) { extensionsData.push(scrollExtensions); } var clsPreview = prefixCls + "-preview"; var cls = [prefixCls, 'wmde-markdown-var', className].filter(Boolean).join(' '); previewProps['source'] = value; var handleChange = (value, viewUpdate) => { setValue(value); onChange && onChange(value, viewUpdate); }; var conentView = /*#__PURE__*/_jsxs("div", { className: prefixCls + "-content", style: { height: codemirrorProps.height }, children: [/*#__PURE__*/_jsx("div", { className: prefixCls + "-content-editor", ref: containerEditor, children: visibleEditor && /*#__PURE__*/_jsx(CodeMirror, _extends({ theme: defaultTheme }, codemirrorProps, { extensions: extensionsData, height: height, ref: codeMirror, onChange: handleChange })) }), /*#__PURE__*/_jsx("div", { className: clsPreview, ref: preview, children: renderPreview ? renderPreview(previewProps, !!visible) : /*#__PURE__*/_jsx(MarkdownPreview, _extends({}, previewProps, { "data-visible": !!visible })) })] }); var clsToolbar = [prefixCls && prefixCls + "-toolbar-warp", prefixCls && toolbarBottom && prefixCls + "-toolbar-bottom"].filter(Boolean).join(' '); var tools = toolbarsFilter ? toolbars.filter(toolbarsFilter) : toolbars; var toolsMode = toolbarsFilter ? toolbarsMode.filter(toolbarsFilter) : toolbarsMode; var toolbarView = hideToolbar && /*#__PURE__*/_jsxs("div", { className: clsToolbar, children: [/*#__PURE__*/_jsx(ToolBar, _extends({}, toolBarProps, { toolbars: tools })), /*#__PURE__*/_jsx(ToolBar, _extends({}, toolBarProps, { toolbars: toolsMode, mode: true }))] }); var child = toolbarBottom ? /*#__PURE__*/_jsxs(Fragment, { children: [conentView, toolbarView] }) : /*#__PURE__*/_jsxs(Fragment, { children: [toolbarView, conentView] }); return /*#__PURE__*/_jsx("div", { className: cls, ref: container, children: child }); }