@uiw/react-md-editor 4.1.5 → 4.1.7

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.
Files changed (56) hide show
  1. package/README.md +16 -1
  2. package/dist/mdeditor.css +5 -0
  3. package/dist/mdeditor.js +2382 -1031
  4. package/dist/mdeditor.min.css +1 -1
  5. package/dist/mdeditor.min.js +1 -1
  6. package/esm/Editor.factory.js +85 -11
  7. package/esm/Types.d.ts +6 -0
  8. package/esm/commands/index.cn.d.ts +2 -1
  9. package/esm/commands/index.cn.js +2 -2
  10. package/esm/commands/index.d.ts +2 -2
  11. package/esm/commands/index.js +2 -2
  12. package/esm/commands/list.d.ts +1 -1
  13. package/esm/commands/list.js +9 -3
  14. package/esm/components/TextArea/Markdown.common.d.ts +3 -5
  15. package/esm/components/TextArea/Markdown.common.js +2 -56
  16. package/esm/components/TextArea/Markdown.d.ts +3 -5
  17. package/esm/components/TextArea/Markdown.factory.d.ts +6 -0
  18. package/esm/components/TextArea/Markdown.factory.js +138 -0
  19. package/esm/components/TextArea/Markdown.js +2 -63
  20. package/esm/components/TextArea/factory.js +6 -2
  21. package/esm/components/TextArea/index.css +5 -0
  22. package/esm/components/TextArea/index.less +5 -0
  23. package/esm/components/TextArea/splitBlocks.d.ts +13 -0
  24. package/esm/components/TextArea/splitBlocks.js +111 -0
  25. package/esm/package.json +1 -0
  26. package/lib/Editor.factory.js +93 -12
  27. package/lib/Types.d.ts +6 -0
  28. package/lib/commands/index.cn.d.ts +2 -1
  29. package/lib/commands/index.cn.js +8 -1
  30. package/lib/commands/index.d.ts +2 -2
  31. package/lib/commands/index.js +6 -0
  32. package/lib/commands/list.d.ts +1 -1
  33. package/lib/commands/list.js +5 -1
  34. package/lib/components/TextArea/Markdown.common.d.ts +3 -5
  35. package/lib/components/TextArea/Markdown.common.js +3 -60
  36. package/lib/components/TextArea/Markdown.d.ts +3 -5
  37. package/lib/components/TextArea/Markdown.factory.d.ts +6 -0
  38. package/lib/components/TextArea/Markdown.factory.js +148 -0
  39. package/lib/components/TextArea/Markdown.js +3 -67
  40. package/lib/components/TextArea/factory.js +6 -2
  41. package/lib/components/TextArea/index.less +5 -0
  42. package/lib/components/TextArea/splitBlocks.d.ts +13 -0
  43. package/lib/components/TextArea/splitBlocks.js +117 -0
  44. package/markdown-editor.css +5 -0
  45. package/package.json +18 -12
  46. package/src/Editor.factory.tsx +83 -4
  47. package/src/Types.ts +6 -0
  48. package/src/commands/index.cn.ts +2 -0
  49. package/src/commands/index.ts +2 -1
  50. package/src/commands/list.tsx +11 -2
  51. package/src/components/TextArea/Markdown.common.tsx +3 -46
  52. package/src/components/TextArea/Markdown.factory.tsx +132 -0
  53. package/src/components/TextArea/Markdown.tsx +3 -55
  54. package/src/components/TextArea/factory.tsx +7 -4
  55. package/src/components/TextArea/index.less +5 -0
  56. package/src/components/TextArea/splitBlocks.ts +114 -0
@@ -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 = ["prefixCls", "className", "value", "commands", "commandsFilter", "direction", "extraCommands", "height", "enableScroll", "visibleDragbar", "highlightEnable", "preview", "fullscreen", "overflow", "previewOptions", "textareaProps", "maxHeight", "minHeight", "autoFocus", "autoFocusEnd", "tabSize", "defaultTabEnable", "onChange", "onStatistics", "onHeightChange", "hideToolbar", "toolbarBottom", "components", "renderTextarea"];
4
- import React, { useEffect, useReducer, useMemo, useRef, useImperativeHandle } from 'react';
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,8 +95,20 @@ 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 ? {} : _ref$previewOptions,
98
+ previewOptions = _ref$previewOptions === void 0 ? DEFAULT_PREVIEW_OPTIONS : _ref$previewOptions,
52
99
  textareaProps = _ref.textareaProps,
100
+ id = _ref.id,
101
+ name = _ref.name,
102
+ required = _ref.required,
103
+ disabled = _ref.disabled,
104
+ readOnly = _ref.readOnly,
105
+ placeholder = _ref.placeholder,
106
+ ariaLabel = _ref['aria-label'],
107
+ ariaLabelledBy = _ref['aria-labelledby'],
108
+ ariaDescribedBy = _ref['aria-describedby'],
109
+ ariaInvalid = _ref['aria-invalid'],
110
+ ariaRequired = _ref['aria-required'],
111
+ ariaErrorMessage = _ref['aria-errormessage'],
53
112
  _ref$maxHeight = _ref.maxHeight,
54
113
  maxHeight = _ref$maxHeight === void 0 ? 1200 : _ref$maxHeight,
55
114
  _ref$minHeight = _ref.minHeight,
@@ -69,10 +128,10 @@ export function createMDEditor(options) {
69
128
  toolbarBottom = _ref$toolbarBottom === void 0 ? false : _ref$toolbarBottom,
70
129
  components = _ref.components,
71
130
  renderTextarea = _ref.renderTextarea,
72
- other = _objectWithoutPropertiesLoose(_ref, _excluded);
131
+ other = _objectWithoutPropertiesLoose(_ref, _excluded2);
73
132
  var cmds = commands.map(item => commandsFilter ? commandsFilter(item, false) : item).filter(Boolean);
74
133
  var extraCmds = extraCommands.map(item => commandsFilter ? commandsFilter(item, true) : item).filter(Boolean);
75
- var _useReducer = useReducer(reducer, {
134
+ var _useReducer2 = useReducer(reducer, {
76
135
  markdown: propsValue,
77
136
  preview: previewType,
78
137
  components,
@@ -88,8 +147,8 @@ export function createMDEditor(options) {
88
147
  fullscreen,
89
148
  barPopup: {}
90
149
  }),
91
- state = _useReducer[0],
92
- dispatch = _useReducer[1];
150
+ state = _useReducer2[0],
151
+ dispatch = _useReducer2[1];
93
152
  var container = useRef(null);
94
153
  var previewRef = useRef(null);
95
154
  var enableScrollRef = useRef(enableScroll);
@@ -195,14 +254,17 @@ export function createMDEditor(options) {
195
254
  };
196
255
  var previewClassName = prefixCls + "-preview " + (previewOptions.className || '');
197
256
  var handlePreviewScroll = e => handleScroll(e, 'preview');
257
+ var previewRenderMs = useRef(0);
258
+ var previewMarkdown = useDeferredValue(usePreviewSource(state.markdown || '', previewRenderMs));
198
259
  var mdPreview = useMemo(() => /*#__PURE__*/_jsx("div", {
199
260
  ref: previewRef,
200
261
  className: previewClassName,
201
- children: /*#__PURE__*/_jsx(PreviewComponent, _extends({}, previewOptions, {
262
+ children: /*#__PURE__*/_jsx(TimedPreview, _extends({}, previewOptions, {
263
+ renderMsRef: previewRenderMs,
202
264
  onScroll: handlePreviewScroll,
203
- source: state.markdown || ''
265
+ source: previewMarkdown
204
266
  }))
205
- }), [previewClassName, previewOptions, state.markdown]);
267
+ }), [previewClassName, previewOptions, previewMarkdown]);
206
268
  var preview = (components == null ? void 0 : components.preview) && (components == null ? void 0 : components.preview(state.markdown || '', state, dispatch));
207
269
  if (preview && /*#__PURE__*/React.isValidElement(preview)) {
208
270
  mdPreview = /*#__PURE__*/_jsx("div", {
@@ -256,7 +318,19 @@ export function createMDEditor(options) {
256
318
  children: [/(edit|live)/.test(state.preview || '') && /*#__PURE__*/_jsx(TextAreaComponent, _extends({
257
319
  className: prefixCls + "-input",
258
320
  prefixCls: prefixCls,
259
- autoFocus: autoFocus
321
+ autoFocus: autoFocus,
322
+ id: id,
323
+ name: name,
324
+ required: required,
325
+ disabled: disabled,
326
+ readOnly: readOnly,
327
+ placeholder: placeholder,
328
+ "aria-label": ariaLabel,
329
+ "aria-labelledby": ariaLabelledBy,
330
+ "aria-describedby": ariaDescribedBy,
331
+ "aria-invalid": ariaInvalid,
332
+ "aria-required": ariaRequired,
333
+ "aria-errormessage": ariaErrorMessage
260
334
  }, textareaProps, {
261
335
  onChange: changeHandle,
262
336
  renderTextarea: (components == null ? void 0 : components.textarea) || renderTextarea,
package/esm/Types.d.ts CHANGED
@@ -18,6 +18,12 @@ export interface MDEditorProps extends Omit<React.HTMLAttributes<HTMLDivElement>
18
18
  * The Markdown value.
19
19
  */
20
20
  value?: string;
21
+ /** Native textarea form attributes. */
22
+ name?: React.TextareaHTMLAttributes<HTMLTextAreaElement>['name'];
23
+ required?: React.TextareaHTMLAttributes<HTMLTextAreaElement>['required'];
24
+ disabled?: React.TextareaHTMLAttributes<HTMLTextAreaElement>['disabled'];
25
+ readOnly?: React.TextareaHTMLAttributes<HTMLTextAreaElement>['readOnly'];
26
+ placeholder?: React.TextareaHTMLAttributes<HTMLTextAreaElement>['placeholder'];
21
27
  /**
22
28
  * Event handler for the `onChange` event.
23
29
  */
@@ -1,6 +1,7 @@
1
1
  import { type ICommand } from './';
2
2
  import { divider } from './divider';
3
3
  import { group } from './group';
4
+ import { makeList } from './list';
4
5
  declare let bold: ICommand;
5
6
  declare let code: ICommand;
6
7
  declare let codeBlock: ICommand;
@@ -30,4 +31,4 @@ declare let table: ICommand;
30
31
  declare let help: ICommand;
31
32
  export declare const getCommands: () => ICommand[];
32
33
  export declare const getExtraCommands: () => ICommand[];
33
- export { title, title1, title2, title3, title4, title5, title6, bold, codeBlock, comment, italic, strikethrough, hr, group, divider, link, quote, code, image, unorderedListCommand, orderedListCommand, checkedListCommand, table, issue, help, codeEdit, codeLive, codePreview, fullscreen, };
34
+ export { title, title1, title2, title3, title4, title5, title6, bold, codeBlock, comment, italic, strikethrough, hr, group, divider, link, quote, code, image, unorderedListCommand, orderedListCommand, checkedListCommand, makeList, table, issue, help, codeEdit, codeLive, codePreview, fullscreen, };
@@ -9,7 +9,7 @@ import { hr as hrInit } from "./hr.js";
9
9
  import { image as imageInit } from "./image.js";
10
10
  import { italic as italicInit } from "./italic.js";
11
11
  import { link as linkInit } from "./link.js";
12
- import { checkedListCommand as checkedListCommandInit, orderedListCommand as orderedListCommandInit, unorderedListCommand as unorderedListCommandInit } from "./list.js";
12
+ import { checkedListCommand as checkedListCommandInit, makeList, orderedListCommand as orderedListCommandInit, unorderedListCommand as unorderedListCommandInit } from "./list.js";
13
13
  import { codeEdit as codeEditInit, codeLive as codeLiveInit, codePreview as codePreviewInit } from "./preview.js";
14
14
  import { quote as quoteInit } from "./quote.js";
15
15
  import { strikethrough as strikethroughInit } from "./strikeThrough.js";
@@ -194,4 +194,4 @@ export var getCommands = () => [bold, italic, strikethrough, hr, group([title1,
194
194
  }
195
195
  }), divider, link, quote, code, codeBlock, comment, image, table, divider, unorderedListCommand, orderedListCommand, checkedListCommand, divider, help];
196
196
  export var getExtraCommands = () => [codeEdit, codeLive, codePreview, divider, fullscreen];
197
- export { title, title1, title2, title3, title4, title5, title6, bold, codeBlock, comment, italic, strikethrough, hr, group, divider, link, quote, code, image, unorderedListCommand, orderedListCommand, checkedListCommand, table, issue, help, codeEdit, codeLive, codePreview, fullscreen };
197
+ export { title, title1, title2, title3, title4, title5, title6, bold, codeBlock, comment, italic, strikethrough, hr, group, divider, link, quote, code, image, unorderedListCommand, orderedListCommand, checkedListCommand, makeList, table, issue, help, codeEdit, codeLive, codePreview, fullscreen };
@@ -10,7 +10,7 @@ import { hr } from './hr';
10
10
  import { image } from './image';
11
11
  import { italic } from './italic';
12
12
  import { link } from './link';
13
- import { checkedListCommand, orderedListCommand, unorderedListCommand } from './list';
13
+ import { checkedListCommand, makeList, orderedListCommand, unorderedListCommand } from './list';
14
14
  import { codeEdit, codeLive, codePreview } from './preview';
15
15
  import { quote } from './quote';
16
16
  import { strikethrough } from './strikeThrough';
@@ -93,4 +93,4 @@ declare class TextAreaCommandOrchestrator implements CommandOrchestrator {
93
93
  getState(): false | TextState;
94
94
  executeCommand(command: ICommand<string>, dispatch?: React.Dispatch<ContextStore>, state?: ExecuteCommandState, shortcuts?: string[]): void;
95
95
  }
96
- export { title, title1, title2, title3, title4, title5, title6, heading, heading1, heading2, heading3, heading4, heading5, heading6, bold, codeBlock, comment, italic, strikethrough, hr, group, divider, link, quote, code, image, unorderedListCommand, orderedListCommand, checkedListCommand, table, issue, help, codeEdit, codeLive, codePreview, fullscreen, getCommands, getExtraCommands, getStateFromTextArea, TextAreaCommandOrchestrator, TextAreaTextApi, };
96
+ export { title, title1, title2, title3, title4, title5, title6, heading, heading1, heading2, heading3, heading4, heading5, heading6, bold, codeBlock, comment, italic, strikethrough, hr, group, divider, link, quote, code, image, unorderedListCommand, orderedListCommand, checkedListCommand, makeList, table, issue, help, codeEdit, codeLive, codePreview, fullscreen, getCommands, getExtraCommands, getStateFromTextArea, TextAreaCommandOrchestrator, TextAreaTextApi, };
@@ -10,7 +10,7 @@ import { hr } from "./hr.js";
10
10
  import { image } from "./image.js";
11
11
  import { italic } from "./italic.js";
12
12
  import { link } from "./link.js";
13
- import { checkedListCommand, orderedListCommand, unorderedListCommand } from "./list.js";
13
+ import { checkedListCommand, makeList, orderedListCommand, unorderedListCommand } from "./list.js";
14
14
  import { codeEdit, codeLive, codePreview } from "./preview.js";
15
15
  import { quote } from "./quote.js";
16
16
  import { strikethrough } from "./strikeThrough.js";
@@ -88,6 +88,6 @@ class TextAreaCommandOrchestrator {
88
88
  }, getStateFromTextArea(this.textArea)), this.textApi, dispatch, state, shortcuts);
89
89
  }
90
90
  }
91
- export { title, title1, title2, title3, title4, title5, title6, heading, heading1, heading2, heading3, heading4, heading5, heading6, bold, codeBlock, comment, italic, strikethrough, hr, group, divider, link, quote, code, image, unorderedListCommand, orderedListCommand, checkedListCommand, table, issue, help, codeEdit, codeLive, codePreview, fullscreen,
91
+ export { title, title1, title2, title3, title4, title5, title6, heading, heading1, heading2, heading3, heading4, heading5, heading6, bold, codeBlock, comment, italic, strikethrough, hr, group, divider, link, quote, code, image, unorderedListCommand, orderedListCommand, checkedListCommand, makeList, table, issue, help, codeEdit, codeLive, codePreview, fullscreen,
92
92
  // Tool method.
93
93
  getCommands, getExtraCommands, getStateFromTextArea, TextAreaCommandOrchestrator, TextAreaTextApi };
@@ -1,6 +1,6 @@
1
1
  import { type ICommand, type ExecuteState, TextAreaTextApi } from './';
2
2
  import { AlterLineFunction } from '../utils/markdownUtils';
3
- export declare const makeList: (state: ExecuteState, api: TextAreaTextApi, insertBefore: string | AlterLineFunction) => void;
3
+ export declare const makeList: (state: ExecuteState, api: TextAreaTextApi, insertBefore: string | AlterLineFunction, selectionStrategy?: "word" | "line") => void;
4
4
  export declare const unorderedListCommand: ICommand;
5
5
  export declare const orderedListCommand: ICommand;
6
6
  export declare const checkedListCommand: ICommand;
@@ -1,8 +1,14 @@
1
1
  import React from 'react';
2
- import { selectWord, getBreaksNeededForEmptyLineBefore, getBreaksNeededForEmptyLineAfter, insertBeforeEachLine } from "../utils/markdownUtils.js";
2
+ import { selectWord, selectLine, getBreaksNeededForEmptyLineBefore, getBreaksNeededForEmptyLineAfter, insertBeforeEachLine } from "../utils/markdownUtils.js";
3
3
  import { jsx as _jsx } from "react/jsx-runtime";
4
- export var makeList = (state, api, insertBefore) => {
5
- var newSelectionRange = selectWord({
4
+ export var makeList = function makeList(state, api, insertBefore, selectionStrategy) {
5
+ if (selectionStrategy === void 0) {
6
+ selectionStrategy = 'word';
7
+ }
8
+ var newSelectionRange = selectionStrategy === 'line' ? selectLine({
9
+ text: state.text,
10
+ selection: state.selection
11
+ }) : selectWord({
6
12
  text: state.text,
7
13
  selection: state.selection,
8
14
  prefix: state.command.prefix
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
- import { type IProps } from '../../Types';
3
- export interface MarkdownProps extends IProps, React.HTMLAttributes<HTMLPreElement> {
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 { EditorContext } from "../../Context.js";
7
- import { jsx as _jsx } from "react/jsx-runtime";
8
- function html2Escape(sHtml) {
9
- return sHtml.replace(/[<&"]/g, c => ({
10
- '<': '&lt;',
11
- '>': '&gt;',
12
- '&': '&amp;',
13
- '"': '&quot;'
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
- import React from 'react';
2
- import { type IProps } from '../../Types';
3
- export interface MarkdownProps extends IProps, React.HTMLAttributes<HTMLPreElement> {
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
+ '<': '&lt;',
14
+ '>': '&gt;',
15
+ '&': '&amp;',
16
+ '"': '&quot;'
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 { EditorContext } from "../../Context.js";
7
- import { jsx as _jsx } from "react/jsx-runtime";
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) => (({ '<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;' } as Record<string, string>)[c]),
14
- // );
15
- // })
16
- .replace(/[<&"]/g, c => ({
17
- '<': '&lt;',
18
- '>': '&gt;',
19
- '&': '&amp;',
20
- '"': '&quot;'
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);
@@ -56,6 +56,10 @@ export function createTextArea(options) {
56
56
  WebkitTextFillColor: 'initial',
57
57
  overflow: 'auto'
58
58
  };
59
+ var inputProps = _extends({}, otherProps);
60
+ if (!inputProps['aria-label'] && !inputProps['aria-labelledby'] && !inputProps.id && !inputProps.title) {
61
+ inputProps['aria-label'] = 'Markdown editor';
62
+ }
59
63
  return /*#__PURE__*/_jsx("div", {
60
64
  ref: warp,
61
65
  className: prefixCls + "-area " + (className || ''),
@@ -65,7 +69,7 @@ export function createTextArea(options) {
65
69
  style: useMinHeight ? {
66
70
  minHeight
67
71
  } : undefined,
68
- children: renderTextarea ? (/*#__PURE__*/React.cloneElement(renderTextarea(_extends({}, otherProps, {
72
+ children: renderTextarea ? (/*#__PURE__*/React.cloneElement(renderTextarea(_extends({}, inputProps, {
69
73
  value: markdown,
70
74
  autoComplete: 'off',
71
75
  spellCheck: 'false',
@@ -91,7 +95,7 @@ export function createTextArea(options) {
91
95
  prefixCls: prefixCls
92
96
  }), /*#__PURE__*/_jsx(Textarea, _extends({
93
97
  prefixCls: prefixCls
94
- }, otherProps, {
98
+ }, inputProps, {
95
99
  style: textStyle
96
100
  }))]
97
101
  })
@@ -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;
@@ -119,6 +119,11 @@
119
119
  .token.bold {
120
120
  font-weight: unset !important;
121
121
  }
122
+ .token.list,
123
+ .token.table {
124
+ display: inline;
125
+ font-size: inherit;
126
+ }
122
127
  .token.title {
123
128
  line-height: unset !important;
124
129
  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[];