@lobehub/editor 1.11.0 → 1.13.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.
Files changed (53) hide show
  1. package/es/editor-kernel/inode/helper.d.ts +9 -6
  2. package/es/editor-kernel/inode/helper.js +27 -0
  3. package/es/editor-kernel/inode/text-node.d.ts +2 -9
  4. package/es/plugins/code/plugin/index.d.ts +1 -1
  5. package/es/plugins/code/plugin/index.js +12 -1
  6. package/es/plugins/codeblock/command/index.d.ts +6 -0
  7. package/es/plugins/codeblock/command/index.js +1 -0
  8. package/es/plugins/codeblock/plugin/CodeHighlighterShiki.d.ts +7 -0
  9. package/es/plugins/codeblock/plugin/CodeHighlighterShiki.js +43 -2
  10. package/es/plugins/codeblock/plugin/FacadeShiki.d.ts +8 -1
  11. package/es/plugins/codeblock/plugin/FacadeShiki.js +95 -6
  12. package/es/plugins/codeblock/plugin/index.js +74 -29
  13. package/es/plugins/common/data-source/json-data-source.d.ts +2 -2
  14. package/es/plugins/common/data-source/json-data-source.js +2 -10
  15. package/es/plugins/common/index.d.ts +1 -1
  16. package/es/plugins/common/index.js +1 -1
  17. package/es/plugins/common/node/cursor.d.ts +3 -1
  18. package/es/plugins/common/node/cursor.js +9 -0
  19. package/es/plugins/common/plugin/index.d.ts +1 -1
  20. package/es/plugins/common/plugin/index.js +28 -1
  21. package/es/plugins/common/plugin/mdReader.d.ts +2 -0
  22. package/es/plugins/common/plugin/mdReader.js +84 -0
  23. package/es/plugins/common/react/ReactPlainText.d.ts +1 -1
  24. package/es/plugins/common/utils/index.d.ts +2 -2
  25. package/es/plugins/hr/plugin/index.js +26 -22
  26. package/es/plugins/link/plugin/index.js +42 -26
  27. package/es/plugins/list/plugin/index.js +121 -63
  28. package/es/plugins/list/utils/index.d.ts +3 -3
  29. package/es/plugins/markdown/data-source/markdown/parse.d.ts +21 -0
  30. package/es/plugins/markdown/data-source/markdown/parse.js +231 -0
  31. package/es/plugins/markdown/data-source/markdown/supersub.d.ts +1 -0
  32. package/es/plugins/markdown/data-source/markdown/supersub.js +14 -0
  33. package/es/plugins/markdown/data-source/markdown-data-source.d.ts +4 -4
  34. package/es/plugins/markdown/data-source/markdown-data-source.js +8 -2
  35. package/es/plugins/markdown/index.d.ts +2 -1
  36. package/es/plugins/markdown/index.js +1 -1
  37. package/es/plugins/markdown/plugin/index.js +135 -2
  38. package/es/plugins/markdown/service/shortcut.d.ts +19 -85
  39. package/es/plugins/markdown/service/shortcut.js +49 -293
  40. package/es/plugins/markdown/service/transformers.d.ts +60 -0
  41. package/es/plugins/markdown/service/transformers.js +286 -0
  42. package/es/plugins/markdown/utils/index.d.ts +45 -1
  43. package/es/plugins/markdown/utils/index.js +147 -1
  44. package/es/plugins/markdown/utils/logger.d.ts +7 -0
  45. package/es/plugins/markdown/utils/logger.js +2 -0
  46. package/es/plugins/math/plugin/index.js +64 -45
  47. package/es/plugins/mention/index.d.ts +1 -0
  48. package/es/plugins/mention/plugin/index.d.ts +4 -1
  49. package/es/plugins/mention/plugin/index.js +27 -11
  50. package/es/plugins/table/plugin/index.js +71 -26
  51. package/es/react/hooks/useEditorState/index.js +43 -21
  52. package/es/types/global.d.ts +64 -0
  53. package/package.json +2 -1
@@ -0,0 +1,231 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
5
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
6
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
7
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
8
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
9
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
10
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
11
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
12
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
13
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
14
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
15
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
16
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
17
+ import { remark } from 'remark';
18
+ import remarkGfm from 'remark-gfm';
19
+ import remarkMath from 'remark-math';
20
+ import { INodeHelper } from "../../../../editor-kernel/inode/helper";
21
+ import { logger } from "../../utils/logger";
22
+ import remarkSupersub from "./supersub";
23
+
24
+ // 使用条件类型确保类型匹配
25
+
26
+ var selfClosingHtmlTags = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
27
+ var MarkdownContext = /*#__PURE__*/function () {
28
+ function MarkdownContext(root) {
29
+ _classCallCheck(this, MarkdownContext);
30
+ _defineProperty(this, "stack", []);
31
+ this.root = root;
32
+ }
33
+ _createClass(MarkdownContext, [{
34
+ key: "push",
35
+ value: function push(html) {
36
+ this.stack.push(html);
37
+ }
38
+ }, {
39
+ key: "isReadingHTML",
40
+ get: function get() {
41
+ return this.stack.length > 0;
42
+ }
43
+ }, {
44
+ key: "last",
45
+ get: function get() {
46
+ return this.stack.at(-1);
47
+ }
48
+ }, {
49
+ key: "pop",
50
+ value: function pop() {
51
+ return this.stack.pop();
52
+ }
53
+ }]);
54
+ return MarkdownContext;
55
+ }();
56
+ function convertMdastToLexical(node, index, ctx) {
57
+ var markdownReaders = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
58
+ switch (node.type) {
59
+ case 'text':
60
+ {
61
+ var textNode = INodeHelper.createTextNode(node.value);
62
+ return textNode;
63
+ }
64
+ default:
65
+ {
66
+ if (markdownReaders[node.type]) {
67
+ var _children = [];
68
+ if ('children' in node && Array.isArray(node.children)) {
69
+ var htmlStack = []; // 当前循环是否包含 HTML 标签
70
+ _children = node.children.reduce(function (ret, child, index) {
71
+ if (child.type === 'html') {
72
+ var tag = child.value.replaceAll(/^<\/?|>$/g, '');
73
+ var isEndTag = child.value.startsWith('</');
74
+ if (selfClosingHtmlTags.has(tag)) {
75
+ // Self-closing tag
76
+ var _reader = markdownReaders['html'];
77
+ if (Array.isArray(_reader)) {
78
+ var _iterator = _createForOfIteratorHelper(_reader),
79
+ _step;
80
+ try {
81
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
82
+ var element = _step.value;
83
+ var inode = element(child, [], index);
84
+ if (inode) {
85
+ ret.push(inode);
86
+ return ret;
87
+ }
88
+ }
89
+ } catch (err) {
90
+ _iterator.e(err);
91
+ } finally {
92
+ _iterator.f();
93
+ }
94
+ } else if (typeof _reader === 'function') {
95
+ var _inode = _reader(child, [], index);
96
+ if (_inode) {
97
+ ret.push(_inode);
98
+ return ret;
99
+ }
100
+ }
101
+ return ret;
102
+ }
103
+ if (isEndTag) {
104
+ var top = ctx.pop();
105
+ htmlStack.pop();
106
+ if ((top === null || top === void 0 ? void 0 : top.tag) !== tag) {
107
+ logger.warn('HTML tag mismatch:', tag);
108
+ ret.push.apply(ret, _toConsumableArray((top === null || top === void 0 ? void 0 : top.children) || []));
109
+ return ret;
110
+ }
111
+ var _reader2 = markdownReaders['html'];
112
+ var _children2 = top.children.flat().filter(Boolean) || [];
113
+ if (Array.isArray(_reader2)) {
114
+ var _iterator2 = _createForOfIteratorHelper(_reader2),
115
+ _step2;
116
+ try {
117
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
118
+ var _element = _step2.value;
119
+ var _inode2 = _element(top.node, _children2, index);
120
+ if (_inode2) {
121
+ ret.push(_inode2);
122
+ return ret;
123
+ }
124
+ }
125
+ } catch (err) {
126
+ _iterator2.e(err);
127
+ } finally {
128
+ _iterator2.f();
129
+ }
130
+ } else if (typeof _reader2 === 'function') {
131
+ var _inode3 = _reader2(top.node, _children2, index);
132
+ if (_inode3) {
133
+ ret.push(_inode3);
134
+ return ret;
135
+ }
136
+ }
137
+ if (top) {
138
+ ret.push.apply(ret, _toConsumableArray(top.children));
139
+ }
140
+ return ret;
141
+ }
142
+ var htmlStackItem = {
143
+ children: [],
144
+ index: index,
145
+ isEndTag: isEndTag,
146
+ node: child,
147
+ tag: tag
148
+ };
149
+ htmlStack.push(htmlStackItem);
150
+ ctx.push(htmlStackItem);
151
+ return ret;
152
+ }
153
+ if (htmlStack.length > 0) {
154
+ var _top = ctx.last;
155
+ if (_top) {
156
+ _top.children.push(convertMdastToLexical(child, index, ctx, markdownReaders));
157
+ }
158
+ return ret;
159
+ }
160
+ ret.push(convertMdastToLexical(child, index, ctx, markdownReaders));
161
+ return ret;
162
+ }, []).filter(Boolean).flat();
163
+ }
164
+ var reader = markdownReaders[node.type];
165
+ if (Array.isArray(reader)) {
166
+ var _iterator3 = _createForOfIteratorHelper(reader),
167
+ _step3;
168
+ try {
169
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
170
+ var element = _step3.value;
171
+ var inode = element(node, _children, index);
172
+ if (inode) {
173
+ return inode;
174
+ }
175
+ }
176
+ } catch (err) {
177
+ _iterator3.e(err);
178
+ } finally {
179
+ _iterator3.f();
180
+ }
181
+ } else if (typeof reader === 'function') {
182
+ var _inode4 = reader(node, _children, index);
183
+ if (_inode4) {
184
+ return _inode4;
185
+ }
186
+ }
187
+ }
188
+
189
+ // Fallback for unsupported nodes
190
+ return null;
191
+ }
192
+ }
193
+ }
194
+ function registerDefaultReaders(markdownReaders) {
195
+ if (!markdownReaders['root']) {
196
+ markdownReaders['root'] = function (node, children) {
197
+ return _objectSpread(_objectSpread({}, INodeHelper.createRootNode()), {}, {
198
+ children: children
199
+ });
200
+ };
201
+ }
202
+ if (!markdownReaders['paragraph']) {
203
+ markdownReaders['paragraph'] = function (node, children) {
204
+ return _objectSpread(_objectSpread({}, INodeHelper.createParagraph()), {}, {
205
+ children: children
206
+ });
207
+ };
208
+ }
209
+ if (!markdownReaders['heading']) {
210
+ markdownReaders['heading'] = function (node, children) {
211
+ var headingType = "h".concat(Math.min(Math.max(node.depth, 1), 6));
212
+ return INodeHelper.createElementNode('heading', {
213
+ children: children,
214
+ direction: 'ltr',
215
+ format: '',
216
+ indent: 0,
217
+ tag: headingType
218
+ });
219
+ };
220
+ }
221
+ }
222
+ export function parseMarkdownToLexical(markdown) {
223
+ var markdownReaders = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
224
+ var ast = remark().use(remarkMath).use(remarkSupersub).use([[remarkGfm, {
225
+ singleTilde: false
226
+ }]]).parse(markdown);
227
+ logger.debug('Parsed MDAST:', ast);
228
+ var ctx = new MarkdownContext(ast);
229
+ registerDefaultReaders(markdownReaders);
230
+ return convertMdastToLexical(ast, 0, ctx, markdownReaders);
231
+ }
@@ -0,0 +1 @@
1
+ export default function remarkSupersub(): void;
@@ -0,0 +1,14 @@
1
+ /* eslint-disable @typescript-eslint/no-this-alias */
2
+ /* eslint-disable @typescript-eslint/no-invalid-this */
3
+ /* eslint-disable unused-imports/no-unused-vars */
4
+ import supersub from 'remark-supersub';
5
+ export default function remarkSupersub() {
6
+ // @ts-expect-error: TS is wrong about `this`.
7
+ // eslint-disable-next-line unicorn/no-this-assignment
8
+ var self = /** @type {Processor} */this;
9
+ var data = self.data();
10
+ var fromMarkdownExtensions = data.fromMarkdownExtensions || (data.fromMarkdownExtensions = []);
11
+ fromMarkdownExtensions.push({
12
+ transforms: [supersub()]
13
+ });
14
+ }
@@ -1,11 +1,11 @@
1
- import { LexicalEditor } from 'lexical';
1
+ import type { LexicalEditor } from 'lexical';
2
2
  import { DataSource } from "../../../editor-kernel";
3
- import { IWriteOptions } from "../../../editor-kernel/data-source";
4
- import { MarkdownShortCutService } from '../service/shortcut';
3
+ import type { IWriteOptions } from "../../../editor-kernel/data-source";
4
+ import type { MarkdownShortCutService } from '../service/shortcut';
5
5
  export default class MarkdownDataSource extends DataSource {
6
6
  protected dataType: string;
7
7
  protected markdownService: MarkdownShortCutService;
8
8
  constructor(dataType: string, markdownService: MarkdownShortCutService);
9
- read(): void;
9
+ read(editor: LexicalEditor, data: string): void;
10
10
  write(editor: LexicalEditor, options?: IWriteOptions): any;
11
11
  }
@@ -29,7 +29,9 @@ import { $isTableSelection } from '@lexical/table';
29
29
  import { $getCharacterOffsets, $getNodeByKey, $getRoot, $getSelection, $isElementNode, $isRangeSelection, $isTextNode } from 'lexical';
30
30
  import { DataSource } from "../../../editor-kernel";
31
31
  import { INodeHelper } from "../../../editor-kernel/inode/helper";
32
+ import { logger } from "../utils/logger";
32
33
  import { MarkdownWriterContext } from "./markdown-writer-context";
34
+ import { parseMarkdownToLexical } from "./markdown/parse";
33
35
  var MarkdownDataSource = /*#__PURE__*/function (_DataSource) {
34
36
  _inherits(MarkdownDataSource, _DataSource);
35
37
  var _super = _createSuper(MarkdownDataSource);
@@ -43,8 +45,12 @@ var MarkdownDataSource = /*#__PURE__*/function (_DataSource) {
43
45
  }
44
46
  _createClass(MarkdownDataSource, [{
45
47
  key: "read",
46
- value: function read() {
47
- throw new Error('MarkdownDataSource not implemented yet!');
48
+ value: function read(editor, data) {
49
+ var inode = {
50
+ root: parseMarkdownToLexical(data, this.markdownService.markdownReaders)
51
+ };
52
+ logger.debug('Parsed Lexical State:', inode);
53
+ editor.setEditorState(editor.parseEditorState(inode));
48
54
  }
49
55
  }, {
50
56
  key: "write",
@@ -1,3 +1,4 @@
1
1
  export { MarkdownPlugin } from './plugin';
2
- export { IMarkdownShortCutService } from './service/shortcut';
2
+ export type { MARKDOWN_READER_LEVEL } from './service/shortcut';
3
+ export { IMarkdownShortCutService, MARKDOWN_READER_LEVEL_HIGH, MARKDOWN_READER_LEVEL_NORMAL, MARKDOWN_WRITER_LEVEL_MAX, } from './service/shortcut';
3
4
  export { isPunctuationChar } from './utils';
@@ -1,3 +1,3 @@
1
1
  export { MarkdownPlugin } from "./plugin";
2
- export { IMarkdownShortCutService } from "./service/shortcut";
2
+ export { IMarkdownShortCutService, MARKDOWN_READER_LEVEL_HIGH, MARKDOWN_READER_LEVEL_NORMAL, MARKDOWN_WRITER_LEVEL_MAX } from "./service/shortcut";
3
3
  export { isPunctuationChar } from "./utils";
@@ -14,11 +14,12 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
14
14
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
15
15
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
16
16
  import { $isCodeNode } from '@lexical/code';
17
- import { $getNodeByKey, $getSelection, $isRangeSelection, $isTextNode, COLLABORATION_TAG, COMMAND_PRIORITY_CRITICAL, HISTORIC_TAG, KEY_ENTER_COMMAND } from 'lexical';
17
+ import { $getNodeByKey, $getSelection, $isRangeSelection, $isTextNode, COLLABORATION_TAG, COMMAND_PRIORITY_CRITICAL, HISTORIC_TAG, KEY_ENTER_COMMAND, PASTE_COMMAND } from 'lexical';
18
18
  import { KernelPlugin } from "../../../editor-kernel/plugin";
19
19
  import MarkdownDataSource from "../data-source/markdown-data-source";
20
+ import { parseMarkdownToLexical } from "../data-source/markdown/parse";
20
21
  import { IMarkdownShortCutService, MarkdownShortCutService } from "../service/shortcut";
21
- import { canContainTransformableMarkdown } from "../utils";
22
+ import { $generateNodesFromSerializedNodes, $insertGeneratedNodes, canContainTransformableMarkdown } from "../utils";
22
23
 
23
24
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
24
25
 
@@ -117,6 +118,138 @@ export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
117
118
  }
118
119
  return false;
119
120
  }, COMMAND_PRIORITY_CRITICAL));
121
+ this.register(editor.registerCommand(PASTE_COMMAND, function (event) {
122
+ if (!(event instanceof ClipboardEvent)) return false;
123
+ var clipboardData = event.clipboardData;
124
+ if (!clipboardData) return false;
125
+
126
+ // Get plain text content
127
+ var text = clipboardData.getData('text/plain');
128
+ var html = clipboardData.getData('text/html');
129
+ if (!text) return false;
130
+
131
+ // Check if content contains markdown patterns
132
+ var hasMarkdownContent = _this2.detectMarkdownContent(text);
133
+ console.log('paste content analysis:', {
134
+ hasHTML: !!html,
135
+ hasMarkdown: hasMarkdownContent,
136
+ markdownPatterns: _this2.getMarkdownPatterns(text),
137
+ text: text.slice(0, 100) + (text.length > 100 ? '...' : '')
138
+ });
139
+ if (hasMarkdownContent) {
140
+ // Handle markdown paste
141
+ return _this2.handleMarkdownPaste(editor, text);
142
+ }
143
+ return false;
144
+ }, COMMAND_PRIORITY_CRITICAL));
145
+ }
146
+
147
+ /**
148
+ * Detect if text contains markdown patterns
149
+ */
150
+ }, {
151
+ key: "detectMarkdownContent",
152
+ value: function detectMarkdownContent(text) {
153
+ var markdownPatterns = [
154
+ // Headers
155
+ /^#{1,6}\s+/m,
156
+ // Bold/italic
157
+ /\*{1,2}[^*]+\*{1,2}/, /__?[^_]+__?/,
158
+ // Code blocks
159
+ /```[\S\s]*```/,
160
+ // Inline code
161
+ /`[^`]+`/,
162
+ // Links
163
+ /\[[^\]]*]\([^)]+\)/,
164
+ // Images
165
+ /!\[[^\]]*]\([^)]+\)/,
166
+ // Lists
167
+ /^[*+-]\s+/m, /^\d+\.\s+/m,
168
+ // Blockquotes
169
+ /^>\s+/m,
170
+ // Tables
171
+ /\|.*\|.*\|/,
172
+ // Horizontal rules
173
+ /^---+$/m, /^\*\*\*+$/m,
174
+ // Strikethrough
175
+ /~~[^~]+~~/];
176
+ return markdownPatterns.some(function (pattern) {
177
+ return pattern.test(text);
178
+ });
179
+ }
180
+
181
+ /**
182
+ * Get specific markdown patterns found in text
183
+ */
184
+ }, {
185
+ key: "getMarkdownPatterns",
186
+ value: function getMarkdownPatterns(text) {
187
+ var patterns = [{
188
+ name: 'headers',
189
+ regex: /^#{1,6}\s+/m
190
+ }, {
191
+ name: 'bold',
192
+ regex: /\*{2}[^*]+\*{2}/
193
+ }, {
194
+ name: 'italic',
195
+ regex: /\*[^*]+\*/
196
+ }, {
197
+ name: 'code-blocks',
198
+ regex: /```[\S\s]*```/
199
+ }, {
200
+ name: 'inline-code',
201
+ regex: /`[^`]+`/
202
+ }, {
203
+ name: 'links',
204
+ regex: /\[[^\]]*]\([^)]+\)/
205
+ }, {
206
+ name: 'images',
207
+ regex: /!\[[^\]]*]\([^)]+\)/
208
+ }, {
209
+ name: 'lists',
210
+ regex: /^[*+-]\s+/m
211
+ }, {
212
+ name: 'ordered-lists',
213
+ regex: /^\d+\.\s+/m
214
+ }, {
215
+ name: 'blockquotes',
216
+ regex: /^>\s+/m
217
+ }, {
218
+ name: 'tables',
219
+ regex: /\|.*\|.*\|/
220
+ }, {
221
+ name: 'horizontal-rules',
222
+ regex: /^---+$/m
223
+ }, {
224
+ name: 'strikethrough',
225
+ regex: /~~[^~]+~~/
226
+ }];
227
+ return patterns.filter(function (_ref2) {
228
+ var regex = _ref2.regex;
229
+ return regex.test(text);
230
+ }).map(function (_ref3) {
231
+ var name = _ref3.name;
232
+ return name;
233
+ });
234
+ }
235
+
236
+ /**
237
+ * Handle markdown paste by parsing and inserting as structured content
238
+ */
239
+ }, {
240
+ key: "handleMarkdownPaste",
241
+ value: function handleMarkdownPaste(editor, text) {
242
+ try {
243
+ // Use the markdown data source to parse the content
244
+ var root = parseMarkdownToLexical(text, this.service.markdownReaders);
245
+ var selection = $getSelection();
246
+ var nodes = $generateNodesFromSerializedNodes(root.children);
247
+ $insertGeneratedNodes(editor, nodes, selection);
248
+ return true;
249
+ } catch (error) {
250
+ console.error('Failed to handle markdown paste:', error);
251
+ }
252
+ return false;
120
253
  }
121
254
  }]);
122
255
  return MarkdownPlugin;
@@ -1,60 +1,7 @@
1
- import { ElementNode, LexicalNode, RangeSelection, TextFormatType, TextNode } from 'lexical';
2
- import { IServiceID } from "../../../types/kernel";
3
- export type TextFormatTransformer = Readonly<{
4
- format?: ReadonlyArray<TextFormatType>;
5
- intraword?: boolean;
6
- process?: (selection: RangeSelection) => void;
7
- tag: string;
8
- type: 'text-format';
9
- }>;
10
- export type TextMatchTransformer = Readonly<{
11
- /**
12
- * For import operations, this function can be used to determine the end index of the match, after `importRegExp` has matched.
13
- * Without this function, the end index will be determined by the length of the match from `importRegExp`. Manually determining the end index can be useful if
14
- * the match from `importRegExp` is not the entire text content of the node. That way, `importRegExp` can be used to match only the start of the node, and `getEndIndex`
15
- * can be used to match the end of the node.
16
- *
17
- * @returns The end index of the match, or false if the match was unsuccessful and a different transformer should be tried.
18
- */
19
- getEndIndex?: (node: TextNode, match: RegExpMatchArray) => number | false;
20
- /**
21
- * This regex determines what text is matched during markdown imports
22
- */
23
- importRegExp?: RegExp;
24
- /**
25
- * This regex determines what text is matched for markdown shortcuts while typing in the editor
26
- */
27
- regExp: RegExp;
28
- /**
29
- * Determines how the matched markdown text should be transformed into a node during the markdown import process
30
- *
31
- * @returns nothing, or a TextNode that may be a child of the new node that is created.
32
- * If a TextNode is returned, text format matching will be applied to it (e.g. bold, italic, etc.)
33
- */
34
- replace?: (node: TextNode, match: RegExpMatchArray) => void | TextNode;
35
- /**
36
- * Single character that allows the transformer to trigger when typed in the editor. This does not affect markdown imports outside of the markdown shortcut plugin.
37
- * If the trigger is matched, the `regExp` will be used to match the text in the second step.
38
- */
39
- trigger?: string;
40
- type: 'text-match';
41
- }>;
42
- export type ElementTransformer = {
43
- regExp: RegExp;
44
- /**
45
- * `replace` is called when markdown is imported or typed in the editor
46
- *
47
- * @return return false to cancel the transform, even though the regex matched. Lexical will then search for the next transformer.
48
- */
49
- replace: (parentNode: ElementNode, children: Array<LexicalNode>, match: Array<string>,
50
- /**
51
- * Whether the match is from an import operation (e.g. through `$convertFromMarkdownString`) or not (e.g. through typing in the editor).
52
- */
53
- isImport: boolean) => boolean | void;
54
- trigger?: 'enter';
55
- type: 'element';
56
- };
57
- export type Transformer = ElementTransformer | TextFormatTransformer | TextMatchTransformer;
1
+ import { ElementNode, LexicalNode, TextNode } from 'lexical';
2
+ import type { IEditorKernel, IServiceID } from "../../../types/kernel";
3
+ import type { MarkdownReaderFunc, TransformerRecord, TransfromerRecordArray } from '../data-source/markdown/parse';
4
+ import type { Transformer } from './transformers';
58
5
  export interface IMarkdownWriterContext {
59
6
  /**
60
7
  * Add processor
@@ -75,7 +22,15 @@ export interface IMarkdownWriterContext {
75
22
  */
76
23
  wrap: (before: string, after: string) => void;
77
24
  }
25
+ export declare const MARKDOWN_WRITER_LEVEL_MAX = 0;
26
+ export declare const MARKDOWN_READER_LEVEL_HIGH = 1;
27
+ export declare const MARKDOWN_READER_LEVEL_NORMAL = 2;
28
+ export type MARKDOWN_READER_LEVEL = typeof MARKDOWN_READER_LEVEL_HIGH | typeof MARKDOWN_READER_LEVEL_NORMAL | typeof MARKDOWN_WRITER_LEVEL_MAX;
78
29
  export interface IMarkdownShortCutService {
30
+ /**
31
+ * Register Markdown reader
32
+ */
33
+ registerMarkdownReader<K extends keyof TransformerRecord>(type: K, reader: MarkdownReaderFunc<K>, level?: MARKDOWN_READER_LEVEL): void;
79
34
  registerMarkdownShortCut(transformer: Transformer): void;
80
35
  registerMarkdownShortCuts(transformers: Transformer[]): void;
81
36
  /**
@@ -93,46 +48,24 @@ export declare class MarkdownShortCutService implements IMarkdownShortCutService
93
48
  private textMatchTransformers;
94
49
  private logger;
95
50
  private _markdownWriters;
96
- constructor(kernel?: import("../../../types/kernel").IEditorKernel | undefined);
97
- get markdownWriters(): Record<string, (ctx: IMarkdownWriterContext, node: LexicalNode) => boolean | void>;
51
+ private _markdownReaders;
52
+ constructor(kernel?: IEditorKernel | undefined);
53
+ get markdownWriters(): Record<string, (_ctx: IMarkdownWriterContext, _node: LexicalNode) => boolean | void>;
54
+ get markdownReaders(): TransfromerRecordArray;
98
55
  private _textFormatTransformersByTrigger;
99
56
  private _textMatchTransformersByTrigger;
100
57
  get textMatchTransformersByTrigger(): Readonly<Record<string, Readonly<{
101
- /**
102
- * For import operations, this function can be used to determine the end index of the match, after `importRegExp` has matched.
103
- * Without this function, the end index will be determined by the length of the match from `importRegExp`. Manually determining the end index can be useful if
104
- * the match from `importRegExp` is not the entire text content of the node. That way, `importRegExp` can be used to match only the start of the node, and `getEndIndex`
105
- * can be used to match the end of the node.
106
- *
107
- * @returns The end index of the match, or false if the match was unsuccessful and a different transformer should be tried.
108
- */
109
58
  getEndIndex?: ((node: TextNode, match: RegExpMatchArray) => number | false) | undefined;
110
- /**
111
- * This regex determines what text is matched during markdown imports
112
- */
113
59
  importRegExp?: RegExp | undefined;
114
- /**
115
- * This regex determines what text is matched for markdown shortcuts while typing in the editor
116
- */
117
60
  regExp: RegExp;
118
- /**
119
- * Determines how the matched markdown text should be transformed into a node during the markdown import process
120
- *
121
- * @returns nothing, or a TextNode that may be a child of the new node that is created.
122
- * If a TextNode is returned, text format matching will be applied to it (e.g. bold, italic, etc.)
123
- */
124
61
  replace?: ((node: TextNode, match: RegExpMatchArray) => void | TextNode) | undefined;
125
- /**
126
- * Single character that allows the transformer to trigger when typed in the editor. This does not affect markdown imports outside of the markdown shortcut plugin.
127
- * If the trigger is matched, the `regExp` will be used to match the text in the second step.
128
- */
129
62
  trigger?: string | undefined;
130
63
  type: "text-match";
131
64
  }>[]>>;
132
65
  get textFormatTransformersByTrigger(): Readonly<Record<string, readonly Readonly<{
133
- format?: readonly TextFormatType[] | undefined;
66
+ format?: readonly import("lexical").TextFormatType[] | undefined;
134
67
  intraword?: boolean | undefined;
135
- process?: ((selection: RangeSelection) => void) | undefined;
68
+ process?: ((selection: import("lexical").RangeSelection) => void) | undefined;
136
69
  tag: string;
137
70
  type: "text-format";
138
71
  }>[]>>;
@@ -141,4 +74,5 @@ export declare class MarkdownShortCutService implements IMarkdownShortCutService
141
74
  testTransformers(parentNode: ElementNode, anchorNode: TextNode, anchorOffset: number, trigger?: 'enter'): boolean;
142
75
  runTransformers(parentNode: ElementNode, anchorNode: TextNode, anchorOffset: number, trigger?: 'enter'): boolean;
143
76
  registerMarkdownWriter(type: string, writer: (ctx: IMarkdownWriterContext, node: LexicalNode) => boolean | void): void;
77
+ registerMarkdownReader<K extends keyof TransformerRecord>(type: K, reader: MarkdownReaderFunc<K>, level?: MARKDOWN_READER_LEVEL): void;
144
78
  }