UNPKG

@uiw/react-md-editor

Version:

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

246 lines (222 loc) 8.66 kB
import _extends from "@babel/runtime/helpers/extends"; import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose"; var _excluded = ["prefixCls", "className", "value", "commands", "commandsFilter", "extraCommands", "height", "toolbarHeight", "enableScroll", "visibleDragbar", "highlightEnable", "preview", "fullscreen", "overflow", "previewOptions", "textareaProps", "maxHeight", "minHeight", "autoFocus", "tabSize", "defaultTabEnable", "onChange", "onHeightChange", "hideToolbar", "toolbarBottom", "components", "renderTextarea"]; import React, { useEffect, useReducer, useMemo, useRef, useImperativeHandle } from 'react'; import MarkdownPreview from '@uiw/react-markdown-preview'; import TextArea from './components/TextArea'; import Toolbar from './components/Toolbar'; import DragBar from './components/DragBar'; import { getCommands, getExtraCommands } from './commands'; import { reducer, EditorContext } from './Context'; import "./index.css"; import { jsx as _jsx } from "react/jsx-runtime"; import { jsxs as _jsxs } from "react/jsx-runtime"; function setGroupPopFalse(data) { if (data === void 0) { data = {}; } Object.keys(data).forEach(keyname => { data[keyname] = false; }); return data; } var InternalMDEditor = (props, ref) => { var _ref = props || {}, { prefixCls = 'w-md-editor', className, value: propsValue, commands = getCommands(), commandsFilter, extraCommands = getExtraCommands(), height = 200, toolbarHeight = 29, enableScroll = true, visibleDragbar = typeof props.visiableDragbar === 'boolean' ? props.visiableDragbar : true, highlightEnable = true, preview: previewType = 'live', fullscreen = false, overflow = true, previewOptions = {}, textareaProps, maxHeight = 1200, minHeight = 100, autoFocus, tabSize = 2, defaultTabEnable = false, onChange: _onChange, onHeightChange, hideToolbar, toolbarBottom = false, components, renderTextarea } = _ref, other = _objectWithoutPropertiesLoose(_ref, _excluded); var cmds = commands.map(item => commandsFilter ? commandsFilter(item, false) : item).filter(Boolean); var extraCmds = extraCommands.map(item => commandsFilter ? commandsFilter(item, true) : item).filter(Boolean); var [state, dispatch] = useReducer(reducer, { markdown: propsValue, preview: previewType, components, height, highlightEnable, tabSize, defaultTabEnable, scrollTop: 0, scrollTopPreview: 0, commands: cmds, extraCommands: extraCmds, fullscreen, barPopup: {} }); var container = useRef(null); var previewRef = useRef(null); var enableScrollRef = useRef(enableScroll); useImperativeHandle(ref, () => _extends({}, state)); useMemo(() => enableScrollRef.current = enableScroll, [enableScroll]); useEffect(() => { var stateInit = {}; if (container.current) { stateInit.container = container.current || undefined; } stateInit.markdown = propsValue || ''; stateInit.barPopup = {}; if (dispatch) { dispatch(_extends({}, state, stateInit)); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); var cls = [className, 'wmde-markdown-var', prefixCls, state.preview ? prefixCls + "-show-" + state.preview : null, state.fullscreen ? prefixCls + "-fullscreen" : null].filter(Boolean).join(' ').trim(); useMemo(() => propsValue !== state.markdown && dispatch({ markdown: propsValue || '' }), [propsValue, state.markdown]); // eslint-disable-next-line react-hooks/exhaustive-deps useMemo(() => previewType !== state.preview && dispatch({ preview: previewType }), [previewType]); // eslint-disable-next-line react-hooks/exhaustive-deps useMemo(() => tabSize !== state.tabSize && dispatch({ tabSize }), [tabSize]); useMemo(() => highlightEnable !== state.highlightEnable && dispatch({ highlightEnable }), // eslint-disable-next-line react-hooks/exhaustive-deps [highlightEnable]); // eslint-disable-next-line react-hooks/exhaustive-deps useMemo(() => autoFocus !== state.autoFocus && dispatch({ autoFocus: autoFocus }), [autoFocus]); useMemo(() => fullscreen !== state.fullscreen && dispatch({ fullscreen: fullscreen }), // eslint-disable-next-line react-hooks/exhaustive-deps [fullscreen]); // eslint-disable-next-line react-hooks/exhaustive-deps useMemo(() => height !== state.height && dispatch({ height: height }), [height]); useMemo(() => height !== state.height && onHeightChange && onHeightChange(state.height, height, state), [height, onHeightChange, state]); var textareaDomRef = useRef(); var active = useRef('preview'); var initScroll = useRef(false); useMemo(() => { textareaDomRef.current = state.textareaWarp; if (state.textareaWarp) { state.textareaWarp.addEventListener('mouseover', () => { active.current = 'text'; }); state.textareaWarp.addEventListener('mouseleave', () => { active.current = 'preview'; }); } }, [state.textareaWarp]); var handleScroll = (e, type) => { if (!enableScrollRef.current) return; var textareaDom = textareaDomRef.current; var previewDom = previewRef.current ? previewRef.current.mdp.current : undefined; if (!initScroll.current) { active.current = type; initScroll.current = true; } if (textareaDom && previewDom) { var scale = (textareaDom.scrollHeight - textareaDom.offsetHeight) / (previewDom.scrollHeight - previewDom.offsetHeight); if (e.target === textareaDom && active.current === 'text') { previewDom.scrollTop = textareaDom.scrollTop / scale; } if (e.target === previewDom && active.current === 'preview') { textareaDom.scrollTop = previewDom.scrollTop * scale; } var scrollTop = 0; if (active.current === 'text') { scrollTop = textareaDom.scrollTop || 0; } else if (active.current === 'preview') { scrollTop = previewDom.scrollTop || 0; } dispatch({ scrollTop }); } }; var mdPreview = useMemo(() => /*#__PURE__*/_jsx(MarkdownPreview, _extends({}, previewOptions, { onScroll: e => handleScroll(e, 'preview'), ref: previewRef, source: state.markdown || '', className: prefixCls + "-preview " + (previewOptions.className || '') })), [prefixCls, previewOptions, state.markdown]); return /*#__PURE__*/_jsx(EditorContext.Provider, { value: _extends({}, state, { dispatch }), children: /*#__PURE__*/_jsxs("div", _extends({ ref: container, className: cls }, other, { onClick: () => { dispatch({ barPopup: _extends({}, setGroupPopFalse(state.barPopup)) }); }, style: _extends({}, other.style, { height: state.height || '100%' }), children: [!hideToolbar && !toolbarBottom && /*#__PURE__*/_jsx(Toolbar, { prefixCls: prefixCls, height: toolbarHeight, overflow: overflow, toolbarBottom: toolbarBottom }), /*#__PURE__*/_jsxs("div", { className: prefixCls + "-content", style: { height: "calc(100% - " + toolbarHeight + "px)" }, children: [/(edit|live)/.test(state.preview || '') && /*#__PURE__*/_jsx(TextArea, _extends({ className: prefixCls + "-input", prefixCls: prefixCls, autoFocus: autoFocus }, textareaProps, { onChange: evn => { _onChange && _onChange(evn.target.value, evn, state); if (textareaProps && textareaProps.onChange) { textareaProps.onChange(evn); } }, renderTextarea: (components == null ? void 0 : components.textarea) || renderTextarea, onScroll: e => handleScroll(e, 'text') })), /(live|preview)/.test(state.preview || '') && mdPreview] }), visibleDragbar && !state.fullscreen && /*#__PURE__*/_jsx(DragBar, { prefixCls: prefixCls, height: state.height, maxHeight: maxHeight, minHeight: minHeight, onChange: newHeight => { dispatch({ height: newHeight }); } }), !hideToolbar && toolbarBottom && /*#__PURE__*/_jsx(Toolbar, { prefixCls: prefixCls, height: toolbarHeight, overflow: overflow, toolbarBottom: toolbarBottom })] })) }); }; var mdEditor = /*#__PURE__*/React.forwardRef(InternalMDEditor); mdEditor.Markdown = MarkdownPreview; export default mdEditor; //# sourceMappingURL=Editor.js.map