@uiw/react-md-editor 4.1.6 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/mdeditor.css +5 -0
- package/dist/mdeditor.js +2378 -1029
- package/dist/mdeditor.min.css +1 -1
- package/dist/mdeditor.min.js +1 -1
- package/esm/Editor.factory.js +70 -17
- package/esm/components/TextArea/Markdown.common.d.ts +3 -5
- package/esm/components/TextArea/Markdown.common.js +2 -56
- package/esm/components/TextArea/Markdown.d.ts +3 -5
- package/esm/components/TextArea/Markdown.factory.d.ts +6 -0
- package/esm/components/TextArea/Markdown.factory.js +138 -0
- package/esm/components/TextArea/Markdown.js +2 -63
- package/esm/components/TextArea/index.css +5 -0
- package/esm/components/TextArea/index.less +5 -0
- package/esm/components/TextArea/splitBlocks.d.ts +13 -0
- package/esm/components/TextArea/splitBlocks.js +111 -0
- package/esm/package.json +1 -0
- package/lib/Editor.factory.js +78 -18
- package/lib/components/TextArea/Markdown.common.d.ts +3 -5
- package/lib/components/TextArea/Markdown.common.js +3 -60
- package/lib/components/TextArea/Markdown.d.ts +3 -5
- package/lib/components/TextArea/Markdown.factory.d.ts +6 -0
- package/lib/components/TextArea/Markdown.factory.js +148 -0
- package/lib/components/TextArea/Markdown.js +3 -67
- package/lib/components/TextArea/index.less +5 -0
- package/lib/components/TextArea/splitBlocks.d.ts +13 -0
- package/lib/components/TextArea/splitBlocks.js +117 -0
- package/markdown-editor.css +5 -0
- package/package.json +18 -12
- package/src/Editor.factory.tsx +64 -12
- package/src/components/TextArea/Markdown.common.tsx +3 -46
- package/src/components/TextArea/Markdown.factory.tsx +132 -0
- package/src/components/TextArea/Markdown.tsx +3 -55
- package/src/components/TextArea/index.less +5 -0
- package/src/components/TextArea/splitBlocks.ts +114 -0
package/esm/Editor.factory.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose";
|
|
3
|
-
var _excluded = ["
|
|
4
|
-
|
|
3
|
+
var _excluded = ["renderMsRef"],
|
|
4
|
+
_excluded2 = ["prefixCls", "className", "value", "commands", "commandsFilter", "direction", "extraCommands", "height", "enableScroll", "visibleDragbar", "highlightEnable", "preview", "fullscreen", "overflow", "previewOptions", "textareaProps", "id", "name", "required", "disabled", "readOnly", "placeholder", "aria-label", "aria-labelledby", "aria-describedby", "aria-invalid", "aria-required", "aria-errormessage", "maxHeight", "minHeight", "autoFocus", "autoFocusEnd", "tabSize", "defaultTabEnable", "onChange", "onStatistics", "onHeightChange", "hideToolbar", "toolbarBottom", "components", "renderTextarea"];
|
|
5
|
+
import React, { useEffect, useLayoutEffect, useReducer, useMemo, useRef, useImperativeHandle } from 'react';
|
|
5
6
|
import { ToolbarVisibility } from "./components/Toolbar/index.js";
|
|
6
7
|
import DragBar from "./components/DragBar/index.js";
|
|
7
8
|
import { getCommands, getExtraCommands, TextAreaCommandOrchestrator } from "./commands/index.js";
|
|
@@ -16,11 +17,57 @@ function setGroupPopFalse(data) {
|
|
|
16
17
|
});
|
|
17
18
|
return data;
|
|
18
19
|
}
|
|
20
|
+
var DEFAULT_PREVIEW_OPTIONS = {};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Lets the preview render after the textarea on React 18+, so typing in a large
|
|
24
|
+
* document stays responsive. Older React versions render it right away, as before.
|
|
25
|
+
*/
|
|
26
|
+
var useDeferredValue = React.useDeferredValue || (value => value);
|
|
27
|
+
var useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
|
|
28
|
+
var SLOW_PREVIEW_MS = 50;
|
|
29
|
+
var MAX_PREVIEW_DELAY_MS = 500;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Keeps the preview in step with every keystroke while it renders fast. Once a preview
|
|
33
|
+
* render takes longer than SLOW_PREVIEW_MS, it waits for a pause in typing as long as
|
|
34
|
+
* that render (at most MAX_PREVIEW_DELAY_MS) before updating.
|
|
35
|
+
* https://github.com/uiwjs/react-md-editor/issues/620
|
|
36
|
+
*/
|
|
37
|
+
function usePreviewSource(markdown, previewRenderMs) {
|
|
38
|
+
var _useReducer = useReducer(count => count + 1, 0),
|
|
39
|
+
rerender = _useReducer[1];
|
|
40
|
+
var shownRef = useRef(markdown);
|
|
41
|
+
if (previewRenderMs.current < SLOW_PREVIEW_MS) {
|
|
42
|
+
shownRef.current = markdown;
|
|
43
|
+
}
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (shownRef.current === markdown) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
var delay = Math.min(previewRenderMs.current, MAX_PREVIEW_DELAY_MS);
|
|
49
|
+
var timer = setTimeout(() => {
|
|
50
|
+
shownRef.current = markdown;
|
|
51
|
+
rerender();
|
|
52
|
+
}, delay);
|
|
53
|
+
return () => clearTimeout(timer);
|
|
54
|
+
}, [markdown, previewRenderMs]);
|
|
55
|
+
return shownRef.current;
|
|
56
|
+
}
|
|
19
57
|
export function createMDEditor(options) {
|
|
20
58
|
var MarkdownPreview = options.MarkdownPreview,
|
|
21
59
|
TextArea = options.TextArea;
|
|
22
60
|
var PreviewComponent = MarkdownPreview;
|
|
23
61
|
var TextAreaComponent = TextArea;
|
|
62
|
+
function TimedPreview(props) {
|
|
63
|
+
var renderMsRef = props.renderMsRef,
|
|
64
|
+
previewProps = _objectWithoutPropertiesLoose(props, _excluded);
|
|
65
|
+
var renderStart = performance.now();
|
|
66
|
+
useIsomorphicLayoutEffect(() => {
|
|
67
|
+
renderMsRef.current = performance.now() - renderStart;
|
|
68
|
+
});
|
|
69
|
+
return /*#__PURE__*/_jsx(PreviewComponent, _extends({}, previewProps));
|
|
70
|
+
}
|
|
24
71
|
var InternalMDEditor = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
25
72
|
var _ref = props || {},
|
|
26
73
|
_ref$prefixCls = _ref.prefixCls,
|
|
@@ -48,7 +95,7 @@ export function createMDEditor(options) {
|
|
|
48
95
|
_ref$overflow = _ref.overflow,
|
|
49
96
|
overflow = _ref$overflow === void 0 ? true : _ref$overflow,
|
|
50
97
|
_ref$previewOptions = _ref.previewOptions,
|
|
51
|
-
previewOptions = _ref$previewOptions === void 0 ?
|
|
98
|
+
previewOptions = _ref$previewOptions === void 0 ? DEFAULT_PREVIEW_OPTIONS : _ref$previewOptions,
|
|
52
99
|
textareaProps = _ref.textareaProps,
|
|
53
100
|
id = _ref.id,
|
|
54
101
|
name = _ref.name,
|
|
@@ -81,10 +128,10 @@ export function createMDEditor(options) {
|
|
|
81
128
|
toolbarBottom = _ref$toolbarBottom === void 0 ? false : _ref$toolbarBottom,
|
|
82
129
|
components = _ref.components,
|
|
83
130
|
renderTextarea = _ref.renderTextarea,
|
|
84
|
-
other = _objectWithoutPropertiesLoose(_ref,
|
|
131
|
+
other = _objectWithoutPropertiesLoose(_ref, _excluded2);
|
|
85
132
|
var cmds = commands.map(item => commandsFilter ? commandsFilter(item, false) : item).filter(Boolean);
|
|
86
133
|
var extraCmds = extraCommands.map(item => commandsFilter ? commandsFilter(item, true) : item).filter(Boolean);
|
|
87
|
-
var
|
|
134
|
+
var _useReducer2 = useReducer(reducer, {
|
|
88
135
|
markdown: propsValue,
|
|
89
136
|
preview: previewType,
|
|
90
137
|
components,
|
|
@@ -100,8 +147,8 @@ export function createMDEditor(options) {
|
|
|
100
147
|
fullscreen,
|
|
101
148
|
barPopup: {}
|
|
102
149
|
}),
|
|
103
|
-
state =
|
|
104
|
-
dispatch =
|
|
150
|
+
state = _useReducer2[0],
|
|
151
|
+
dispatch = _useReducer2[1];
|
|
105
152
|
var container = useRef(null);
|
|
106
153
|
var previewRef = useRef(null);
|
|
107
154
|
var enableScrollRef = useRef(enableScroll);
|
|
@@ -187,12 +234,15 @@ export function createMDEditor(options) {
|
|
|
187
234
|
initScroll.current = true;
|
|
188
235
|
}
|
|
189
236
|
if (textareaDom && previewDom) {
|
|
190
|
-
var
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
237
|
+
var inputRange = Math.max(0, textareaDom.scrollHeight - textareaDom.offsetHeight);
|
|
238
|
+
var previewRange = Math.max(0, previewDom.scrollHeight - previewDom.offsetHeight);
|
|
239
|
+
if (inputRange > 0 && previewRange > 0) {
|
|
240
|
+
if (e.target === textareaDom && active.current === 'text') {
|
|
241
|
+
previewDom.scrollTop = textareaDom.scrollTop / inputRange * previewRange;
|
|
242
|
+
}
|
|
243
|
+
if (e.target === previewDom && active.current === 'preview') {
|
|
244
|
+
textareaDom.scrollTop = previewDom.scrollTop / previewRange * inputRange;
|
|
245
|
+
}
|
|
196
246
|
}
|
|
197
247
|
var scrollTop = 0;
|
|
198
248
|
if (active.current === 'text') {
|
|
@@ -207,14 +257,17 @@ export function createMDEditor(options) {
|
|
|
207
257
|
};
|
|
208
258
|
var previewClassName = prefixCls + "-preview " + (previewOptions.className || '');
|
|
209
259
|
var handlePreviewScroll = e => handleScroll(e, 'preview');
|
|
260
|
+
var previewRenderMs = useRef(0);
|
|
261
|
+
var previewMarkdown = useDeferredValue(usePreviewSource(state.markdown || '', previewRenderMs));
|
|
210
262
|
var mdPreview = useMemo(() => /*#__PURE__*/_jsx("div", {
|
|
211
263
|
ref: previewRef,
|
|
212
264
|
className: previewClassName,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
265
|
+
onScroll: handlePreviewScroll,
|
|
266
|
+
children: /*#__PURE__*/_jsx(TimedPreview, _extends({}, previewOptions, {
|
|
267
|
+
renderMsRef: previewRenderMs,
|
|
268
|
+
source: previewMarkdown
|
|
216
269
|
}))
|
|
217
|
-
}), [previewClassName, previewOptions,
|
|
270
|
+
}), [previewClassName, previewOptions, previewMarkdown]);
|
|
218
271
|
var preview = (components == null ? void 0 : components.preview) && (components == null ? void 0 : components.preview(state.markdown || '', state, dispatch));
|
|
219
272
|
if (preview && /*#__PURE__*/React.isValidElement(preview)) {
|
|
220
273
|
mdPreview = /*#__PURE__*/_jsx("div", {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
}
|
|
5
|
-
export default function Markdown(props: MarkdownProps): import("react/jsx-runtime").JSX.Element;
|
|
1
|
+
export type { MarkdownProps } from './Markdown.factory';
|
|
2
|
+
declare const _default: (props: import("./Markdown.factory").MarkdownProps) => import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
export default _default;
|
|
@@ -1,57 +1,3 @@
|
|
|
1
|
-
import _taggedTemplateLiteralLoose from "@babel/runtime/helpers/taggedTemplateLiteralLoose";
|
|
2
|
-
var _templateObject;
|
|
3
|
-
import React, { useContext, useEffect } from 'react';
|
|
4
|
-
import { rehype } from 'rehype';
|
|
5
1
|
import rehypePrism from 'rehype-prism-plus/common';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
function html2Escape(sHtml) {
|
|
9
|
-
return sHtml.replace(/[<&"]/g, c => ({
|
|
10
|
-
'<': '<',
|
|
11
|
-
'>': '>',
|
|
12
|
-
'&': '&',
|
|
13
|
-
'"': '"'
|
|
14
|
-
})[c]);
|
|
15
|
-
}
|
|
16
|
-
export default function Markdown(props) {
|
|
17
|
-
var prefixCls = props.prefixCls;
|
|
18
|
-
var _useContext = useContext(EditorContext),
|
|
19
|
-
_useContext$markdown = _useContext.markdown,
|
|
20
|
-
markdown = _useContext$markdown === void 0 ? '' : _useContext$markdown,
|
|
21
|
-
highlightEnable = _useContext.highlightEnable,
|
|
22
|
-
dispatch = _useContext.dispatch;
|
|
23
|
-
var preRef = /*#__PURE__*/React.createRef();
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
if (preRef.current && dispatch) {
|
|
26
|
-
dispatch({
|
|
27
|
-
textareaPre: preRef.current
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
31
|
-
}, []);
|
|
32
|
-
if (!markdown) {
|
|
33
|
-
return /*#__PURE__*/_jsx("pre", {
|
|
34
|
-
ref: preRef,
|
|
35
|
-
className: prefixCls + "-text-pre wmde-markdown-color"
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
var mdStr = "<pre class=\"language-markdown " + prefixCls + "-text-pre wmde-markdown-color\"><code class=\"language-markdown\">" + html2Escape(String.raw(_templateObject || (_templateObject = _taggedTemplateLiteralLoose(["", ""])), markdown)) + "\n</code></pre>";
|
|
39
|
-
if (highlightEnable) {
|
|
40
|
-
try {
|
|
41
|
-
mdStr = rehype().data('settings', {
|
|
42
|
-
fragment: true
|
|
43
|
-
})
|
|
44
|
-
// https://github.com/uiwjs/react-md-editor/issues/593
|
|
45
|
-
// @ts-ignore
|
|
46
|
-
.use(rehypePrism, {
|
|
47
|
-
ignoreMissing: true
|
|
48
|
-
}).processSync(mdStr).toString();
|
|
49
|
-
} catch (error) {}
|
|
50
|
-
}
|
|
51
|
-
return /*#__PURE__*/React.createElement('div', {
|
|
52
|
-
className: 'wmde-markdown-color',
|
|
53
|
-
dangerouslySetInnerHTML: {
|
|
54
|
-
__html: mdStr || ''
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
}
|
|
2
|
+
import { createMarkdown } from './Markdown.factory';
|
|
3
|
+
export default createMarkdown(rehypePrism);
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
}
|
|
5
|
-
export default function Markdown(props: MarkdownProps): import("react/jsx-runtime").JSX.Element;
|
|
1
|
+
export type { MarkdownProps } from './Markdown.factory';
|
|
2
|
+
declare const _default: (props: import("./Markdown.factory").MarkdownProps) => import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type rehypePrismPlus from 'rehype-prism-plus';
|
|
3
|
+
import { type IProps } from '../../Types';
|
|
4
|
+
export interface MarkdownProps extends IProps, React.HTMLAttributes<HTMLPreElement> {
|
|
5
|
+
}
|
|
6
|
+
export declare function createMarkdown(rehypePrism: typeof rehypePrismPlus): (props: MarkdownProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import React, { useContext, useEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { rehype } from 'rehype';
|
|
3
|
+
import { EditorContext } from "../../Context.js";
|
|
4
|
+
import { splitBlocks } from "./splitBlocks.js";
|
|
5
|
+
/**
|
|
6
|
+
* Prism's markdown grammar takes quadratic time on long lines, so a single base64 image
|
|
7
|
+
* line can block the editor for minutes. Blocks with such a line are shown uncoloured.
|
|
8
|
+
*/
|
|
9
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
|
+
var MAX_HIGHLIGHT_LINE_LENGTH = 1000;
|
|
11
|
+
function html2Escape(sHtml) {
|
|
12
|
+
return sHtml.replace(/[<&"]/g, c => ({
|
|
13
|
+
'<': '<',
|
|
14
|
+
'>': '>',
|
|
15
|
+
'&': '&',
|
|
16
|
+
'"': '"'
|
|
17
|
+
})[c]);
|
|
18
|
+
}
|
|
19
|
+
function hasLongLine(text) {
|
|
20
|
+
var lineStart = 0;
|
|
21
|
+
while (lineStart <= text.length) {
|
|
22
|
+
var lineEnd = text.indexOf('\n', lineStart);
|
|
23
|
+
var end = lineEnd === -1 ? text.length : lineEnd;
|
|
24
|
+
if (end - lineStart > MAX_HIGHLIGHT_LINE_LENGTH) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
lineStart = end + 1;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
function getCodeInnerHtml(html) {
|
|
32
|
+
var codeStart = html.indexOf('<code');
|
|
33
|
+
var contentStart = html.indexOf('>', codeStart) + 1;
|
|
34
|
+
var contentEnd = html.lastIndexOf('</code>');
|
|
35
|
+
return html.slice(contentStart, contentEnd);
|
|
36
|
+
}
|
|
37
|
+
var MarkdownBlock = /*#__PURE__*/React.memo(function MarkdownBlock(props) {
|
|
38
|
+
return /*#__PURE__*/React.createElement('span', {
|
|
39
|
+
dangerouslySetInnerHTML: {
|
|
40
|
+
__html: props.html
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
export function createMarkdown(rehypePrism) {
|
|
45
|
+
var processor = rehype().data('settings', {
|
|
46
|
+
fragment: true
|
|
47
|
+
})
|
|
48
|
+
// https://github.com/uiwjs/react-md-editor/issues/593
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
.use(rehypePrism, {
|
|
51
|
+
ignoreMissing: true
|
|
52
|
+
});
|
|
53
|
+
function highlightBlock(block) {
|
|
54
|
+
var escaped = html2Escape(block);
|
|
55
|
+
if (hasLongLine(block)) {
|
|
56
|
+
return escaped;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
var html = processor.processSync("<pre><code class=\"language-markdown\">" + escaped + "</code></pre>").toString();
|
|
60
|
+
return getCodeInnerHtml(html);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return escaped;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Highlighting runs per block, and blocks whose text did not change reuse their cached
|
|
68
|
+
* HTML and DOM, so typing in a large document only re-highlights the edited block.
|
|
69
|
+
* https://github.com/uiwjs/react-md-editor/issues/620
|
|
70
|
+
*/
|
|
71
|
+
return function Markdown(props) {
|
|
72
|
+
var prefixCls = props.prefixCls;
|
|
73
|
+
var _useContext = useContext(EditorContext),
|
|
74
|
+
_useContext$markdown = _useContext.markdown,
|
|
75
|
+
markdown = _useContext$markdown === void 0 ? '' : _useContext$markdown,
|
|
76
|
+
highlightEnable = _useContext.highlightEnable,
|
|
77
|
+
dispatch = _useContext.dispatch;
|
|
78
|
+
var preRef = useRef(null);
|
|
79
|
+
var cacheRef = useRef(new Map());
|
|
80
|
+
var nextIdRef = useRef(0);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (preRef.current && dispatch) {
|
|
83
|
+
dispatch({
|
|
84
|
+
textareaPre: preRef.current
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
88
|
+
}, []);
|
|
89
|
+
var blocks = useMemo(() => {
|
|
90
|
+
if (!highlightEnable) {
|
|
91
|
+
cacheRef.current = new Map();
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
var cache = new Map();
|
|
95
|
+
var occurrences = new Map();
|
|
96
|
+
var result = splitBlocks(markdown).map(block => {
|
|
97
|
+
var highlighted = cacheRef.current.get(block) || cache.get(block);
|
|
98
|
+
if (!highlighted) {
|
|
99
|
+
highlighted = {
|
|
100
|
+
id: nextIdRef.current++,
|
|
101
|
+
html: highlightBlock(block)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
cache.set(block, highlighted);
|
|
105
|
+
var occurrence = occurrences.get(block) || 0;
|
|
106
|
+
occurrences.set(block, occurrence + 1);
|
|
107
|
+
return {
|
|
108
|
+
key: highlighted.id + "-" + occurrence,
|
|
109
|
+
html: highlighted.html
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
cacheRef.current = cache;
|
|
113
|
+
return result;
|
|
114
|
+
}, [markdown, highlightEnable]);
|
|
115
|
+
if (!markdown) {
|
|
116
|
+
return /*#__PURE__*/_jsx("pre", {
|
|
117
|
+
ref: preRef,
|
|
118
|
+
className: prefixCls + "-text-pre wmde-markdown-color"
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return /*#__PURE__*/_jsx("div", {
|
|
122
|
+
className: "wmde-markdown-color",
|
|
123
|
+
children: /*#__PURE__*/_jsx("pre", {
|
|
124
|
+
ref: preRef,
|
|
125
|
+
className: "language-markdown " + prefixCls + "-text-pre wmde-markdown-color",
|
|
126
|
+
children: highlightEnable ? /*#__PURE__*/_jsxs("code", {
|
|
127
|
+
className: "language-markdown code-highlight",
|
|
128
|
+
children: [blocks.map(block => /*#__PURE__*/_jsx(MarkdownBlock, {
|
|
129
|
+
html: block.html
|
|
130
|
+
}, block.key)), '\n']
|
|
131
|
+
}) : /*#__PURE__*/_jsx("code", {
|
|
132
|
+
className: "language-markdown",
|
|
133
|
+
children: markdown + "\n"
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
}
|
|
@@ -1,64 +1,3 @@
|
|
|
1
|
-
import _taggedTemplateLiteralLoose from "@babel/runtime/helpers/taggedTemplateLiteralLoose";
|
|
2
|
-
var _templateObject;
|
|
3
|
-
import React, { useContext, useEffect } from 'react';
|
|
4
|
-
import { rehype } from 'rehype';
|
|
5
1
|
import rehypePrism from 'rehype-prism-plus';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
function html2Escape(sHtml) {
|
|
9
|
-
return sHtml
|
|
10
|
-
// .replace(/```(\w+)?([\s\S]*?)(\s.+)?```/g, (str: string) => {
|
|
11
|
-
// return str.replace(
|
|
12
|
-
// /[<&"]/g,
|
|
13
|
-
// (c: string) => (({ '<': '<', '>': '>', '&': '&', '"': '"' } as Record<string, string>)[c]),
|
|
14
|
-
// );
|
|
15
|
-
// })
|
|
16
|
-
.replace(/[<&"]/g, c => ({
|
|
17
|
-
'<': '<',
|
|
18
|
-
'>': '>',
|
|
19
|
-
'&': '&',
|
|
20
|
-
'"': '"'
|
|
21
|
-
})[c]);
|
|
22
|
-
}
|
|
23
|
-
export default function Markdown(props) {
|
|
24
|
-
var prefixCls = props.prefixCls;
|
|
25
|
-
var _useContext = useContext(EditorContext),
|
|
26
|
-
_useContext$markdown = _useContext.markdown,
|
|
27
|
-
markdown = _useContext$markdown === void 0 ? '' : _useContext$markdown,
|
|
28
|
-
highlightEnable = _useContext.highlightEnable,
|
|
29
|
-
dispatch = _useContext.dispatch;
|
|
30
|
-
var preRef = /*#__PURE__*/React.createRef();
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
if (preRef.current && dispatch) {
|
|
33
|
-
dispatch({
|
|
34
|
-
textareaPre: preRef.current
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
38
|
-
}, []);
|
|
39
|
-
if (!markdown) {
|
|
40
|
-
return /*#__PURE__*/_jsx("pre", {
|
|
41
|
-
ref: preRef,
|
|
42
|
-
className: prefixCls + "-text-pre wmde-markdown-color"
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
var mdStr = "<pre class=\"language-markdown " + prefixCls + "-text-pre wmde-markdown-color\"><code class=\"language-markdown\">" + html2Escape(String.raw(_templateObject || (_templateObject = _taggedTemplateLiteralLoose(["", ""])), markdown)) + "\n</code></pre>";
|
|
46
|
-
if (highlightEnable) {
|
|
47
|
-
try {
|
|
48
|
-
mdStr = rehype().data('settings', {
|
|
49
|
-
fragment: true
|
|
50
|
-
})
|
|
51
|
-
// https://github.com/uiwjs/react-md-editor/issues/593
|
|
52
|
-
// @ts-ignore
|
|
53
|
-
.use(rehypePrism, {
|
|
54
|
-
ignoreMissing: true
|
|
55
|
-
}).processSync(mdStr).toString();
|
|
56
|
-
} catch (error) {}
|
|
57
|
-
}
|
|
58
|
-
return /*#__PURE__*/React.createElement('div', {
|
|
59
|
-
className: 'wmde-markdown-color',
|
|
60
|
-
dangerouslySetInnerHTML: {
|
|
61
|
-
__html: mdStr || ''
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
}
|
|
2
|
+
import { createMarkdown } from './Markdown.factory';
|
|
3
|
+
export default createMarkdown(rehypePrism);
|
|
@@ -113,6 +113,11 @@
|
|
|
113
113
|
.w-md-editor-text-pre .token.bold {
|
|
114
114
|
font-weight: unset !important;
|
|
115
115
|
}
|
|
116
|
+
.w-md-editor-text-pre .token.list,
|
|
117
|
+
.w-md-editor-text-pre .token.table {
|
|
118
|
+
display: inline;
|
|
119
|
+
font-size: inherit;
|
|
120
|
+
}
|
|
116
121
|
.w-md-editor-text-pre .token.title {
|
|
117
122
|
line-height: unset !important;
|
|
118
123
|
font-size: unset !important;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splits markdown into blocks that Prism's markdown grammar highlights the same way
|
|
3
|
+
* on their own as it does in the full document, so unchanged blocks can be cached.
|
|
4
|
+
* Joining the returned blocks always yields the original string.
|
|
5
|
+
*
|
|
6
|
+
* A block ends where a run of blank lines starts, so each block keeps its leading blank
|
|
7
|
+
* lines (indented code needs them). No split happens inside a ``` fence, front matter or
|
|
8
|
+
* multiline markup or link references, or right before a `---` line, which Prism
|
|
9
|
+
* would read as front matter. Whitespace-only lines stay in their block because
|
|
10
|
+
* Prism's inline emphasis can span them.
|
|
11
|
+
* Fences follow Prism's rule, not CommonMark's, so the split matches what Prism sees.
|
|
12
|
+
*/
|
|
13
|
+
export declare function splitBlocks(markdown: string): string[];
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
var FENCE_OPEN = /^```/;
|
|
2
|
+
var FENCE_CLOSE = /^```\r?\n?$/;
|
|
3
|
+
var BLANK_LINE = /^[ \t]*\r?\n?$/;
|
|
4
|
+
var FRONT_MATTER_FENCE = /^---\r?\n?$/;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Splits markdown into blocks that Prism's markdown grammar highlights the same way
|
|
8
|
+
* on their own as it does in the full document, so unchanged blocks can be cached.
|
|
9
|
+
* Joining the returned blocks always yields the original string.
|
|
10
|
+
*
|
|
11
|
+
* A block ends where a run of blank lines starts, so each block keeps its leading blank
|
|
12
|
+
* lines (indented code needs them). No split happens inside a ``` fence, front matter or
|
|
13
|
+
* multiline markup or link references, or right before a `---` line, which Prism
|
|
14
|
+
* would read as front matter. Whitespace-only lines stay in their block because
|
|
15
|
+
* Prism's inline emphasis can span them.
|
|
16
|
+
* Fences follow Prism's rule, not CommonMark's, so the split matches what Prism sees.
|
|
17
|
+
*/
|
|
18
|
+
export function splitBlocks(markdown) {
|
|
19
|
+
var lines = markdown.match(/[^\n]*\n|[^\n]+$/g) || [];
|
|
20
|
+
var blocks = [];
|
|
21
|
+
var current = '';
|
|
22
|
+
var pendingSplit = -1;
|
|
23
|
+
var inFence = false;
|
|
24
|
+
var inFrontMatter = /^(?:\s*[\r\n])?---(?:\r?\n|$)/.test(markdown);
|
|
25
|
+
var frontMatterStarted = false;
|
|
26
|
+
var syntax = {
|
|
27
|
+
end: '',
|
|
28
|
+
quote: '',
|
|
29
|
+
brackets: 0,
|
|
30
|
+
subset: 0
|
|
31
|
+
};
|
|
32
|
+
var previousIsBlank = true;
|
|
33
|
+
lines.forEach(line => {
|
|
34
|
+
var isBlank = BLANK_LINE.test(line);
|
|
35
|
+
var canSplit = !inFence && !inFrontMatter && !syntax.end && !syntax.brackets;
|
|
36
|
+
if (/^\r?\n$/.test(line) && !previousIsBlank && canSplit) {
|
|
37
|
+
pendingSplit = current.length;
|
|
38
|
+
}
|
|
39
|
+
if (!isBlank && pendingSplit > 0) {
|
|
40
|
+
if (!FRONT_MATTER_FENCE.test(line)) {
|
|
41
|
+
blocks.push(current.slice(0, pendingSplit));
|
|
42
|
+
current = current.slice(pendingSplit);
|
|
43
|
+
}
|
|
44
|
+
pendingSplit = -1;
|
|
45
|
+
}
|
|
46
|
+
current += line;
|
|
47
|
+
previousIsBlank = isBlank;
|
|
48
|
+
if (inFrontMatter) {
|
|
49
|
+
if (FRONT_MATTER_FENCE.test(line)) {
|
|
50
|
+
inFrontMatter = !frontMatterStarted;
|
|
51
|
+
frontMatterStarted = true;
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (inFence) {
|
|
56
|
+
inFence = !FENCE_CLOSE.test(line);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!syntax.end && FENCE_OPEN.test(line)) {
|
|
60
|
+
inFence = true;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
updateSyntax(line, syntax);
|
|
64
|
+
});
|
|
65
|
+
if (current) {
|
|
66
|
+
blocks.push(current);
|
|
67
|
+
}
|
|
68
|
+
return blocks;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Keep potential multiline Prism tokens together. Unclosed syntax conservatively
|
|
72
|
+
// keeps the rest of the document in one block until the user closes it.
|
|
73
|
+
function updateSyntax(line, state) {
|
|
74
|
+
var reference = false;
|
|
75
|
+
for (var i = 0; i < line.length; i++) {
|
|
76
|
+
var char = line[i];
|
|
77
|
+
if (state.end && state.end !== '>') {
|
|
78
|
+
var end = line.indexOf(state.end, i);
|
|
79
|
+
if (end === -1) return;
|
|
80
|
+
i = end + state.end.length - 1;
|
|
81
|
+
state.end = '';
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (state.end === '>') {
|
|
85
|
+
if (state.quote) {
|
|
86
|
+
if (char === state.quote) state.quote = '';
|
|
87
|
+
} else if (char === '"' || char === "'") {
|
|
88
|
+
state.quote = char;
|
|
89
|
+
} else if (char === '[') {
|
|
90
|
+
state.subset++;
|
|
91
|
+
} else if (char === ']' && state.subset) {
|
|
92
|
+
state.subset--;
|
|
93
|
+
} else if (char === '>' && !state.subset) {
|
|
94
|
+
state.end = '';
|
|
95
|
+
}
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (char === '\\') {
|
|
99
|
+
i++;
|
|
100
|
+
} else if (char === '<' && /[a-z!?/]/i.test(line[i + 1] || '')) {
|
|
101
|
+
state.end = line.startsWith('<!--', i) ? '-->' : line.startsWith('<![CDATA[', i) ? ']]>' : line.startsWith('<?', i) ? '?>' : '>';
|
|
102
|
+
} else if (char === '[') {
|
|
103
|
+
state.brackets++;
|
|
104
|
+
} else if (char === ']') {
|
|
105
|
+
state.brackets = Math.max(0, state.brackets - 1);
|
|
106
|
+
reference = line[i + 1] === ':';
|
|
107
|
+
} else if (reference && (char === '"' || char === "'" || char === '(')) {
|
|
108
|
+
state.end = char === '(' ? ')' : char;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
package/esm/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|