@lobehub/editor 1.11.0 → 1.12.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/es/editor-kernel/inode/helper.d.ts +9 -6
- package/es/editor-kernel/inode/helper.js +27 -0
- package/es/editor-kernel/inode/text-node.d.ts +2 -9
- package/es/plugins/code/plugin/index.d.ts +1 -1
- package/es/plugins/code/plugin/index.js +12 -1
- package/es/plugins/codeblock/command/index.d.ts +6 -0
- package/es/plugins/codeblock/command/index.js +1 -0
- package/es/plugins/codeblock/plugin/CodeHighlighterShiki.d.ts +7 -0
- package/es/plugins/codeblock/plugin/CodeHighlighterShiki.js +43 -2
- package/es/plugins/codeblock/plugin/FacadeShiki.d.ts +8 -1
- package/es/plugins/codeblock/plugin/FacadeShiki.js +95 -6
- package/es/plugins/codeblock/plugin/index.js +74 -29
- package/es/plugins/common/data-source/json-data-source.d.ts +2 -2
- package/es/plugins/common/data-source/json-data-source.js +2 -10
- package/es/plugins/common/index.d.ts +1 -1
- package/es/plugins/common/index.js +1 -1
- package/es/plugins/common/node/cursor.d.ts +3 -1
- package/es/plugins/common/node/cursor.js +9 -0
- package/es/plugins/common/plugin/index.d.ts +1 -1
- package/es/plugins/common/plugin/index.js +28 -1
- package/es/plugins/common/plugin/mdReader.d.ts +2 -0
- package/es/plugins/common/plugin/mdReader.js +59 -0
- package/es/plugins/common/react/ReactPlainText.d.ts +1 -1
- package/es/plugins/common/utils/index.d.ts +2 -2
- package/es/plugins/hr/plugin/index.js +26 -22
- package/es/plugins/link/plugin/index.js +42 -26
- package/es/plugins/list/plugin/index.js +121 -63
- package/es/plugins/list/utils/index.d.ts +3 -3
- package/es/plugins/markdown/data-source/markdown/parse.d.ts +10 -0
- package/es/plugins/markdown/data-source/markdown/parse.js +82 -0
- package/es/plugins/markdown/data-source/markdown/supersub.d.ts +1 -0
- package/es/plugins/markdown/data-source/markdown/supersub.js +14 -0
- package/es/plugins/markdown/data-source/markdown-data-source.d.ts +4 -4
- package/es/plugins/markdown/data-source/markdown-data-source.js +8 -2
- package/es/plugins/markdown/plugin/index.js +135 -2
- package/es/plugins/markdown/service/shortcut.d.ts +15 -85
- package/es/plugins/markdown/service/shortcut.js +34 -293
- package/es/plugins/markdown/service/transformers.d.ts +60 -0
- package/es/plugins/markdown/service/transformers.js +286 -0
- package/es/plugins/markdown/utils/index.d.ts +45 -1
- package/es/plugins/markdown/utils/index.js +147 -1
- package/es/plugins/markdown/utils/logger.d.ts +7 -0
- package/es/plugins/markdown/utils/logger.js +2 -0
- package/es/plugins/math/plugin/index.js +64 -45
- package/es/plugins/table/plugin/index.js +71 -26
- package/es/react/hooks/useEditorState/index.js +43 -21
- package/es/types/global.d.ts +64 -0
- package/package.json +2 -1
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
2
|
+
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."); }
|
|
3
|
+
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
4
|
+
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
5
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
6
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
7
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
8
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
9
|
+
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; } } }; }
|
|
10
|
+
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); }
|
|
11
|
+
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; }
|
|
12
|
+
import { $createRangeSelection, $getSelection, $isLineBreakNode, $isRangeSelection, $isRootOrShadowRoot, $isTextNode, $setSelection } from 'lexical';
|
|
13
|
+
import { PUNCTUATION_OR_SPACE, getOpenTagStartIndex, isEqualSubString } from "../utils";
|
|
14
|
+
export function testElementTransformers(parentNode, anchorNode, anchorOffset, elementTransformers, fromTrigger) {
|
|
15
|
+
var grandParentNode = parentNode.getParent();
|
|
16
|
+
if (!$isRootOrShadowRoot(grandParentNode) || parentNode.getFirstChild() !== anchorNode) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
var textContent = anchorNode.getTextContent();
|
|
20
|
+
|
|
21
|
+
// Checking for anchorOffset position to prevent any checks for cases when caret is too far
|
|
22
|
+
// from a line start to be a part of block-level markdown trigger.
|
|
23
|
+
//
|
|
24
|
+
// TODO:
|
|
25
|
+
// Can have a quick check if caret is close enough to the beginning of the string (e.g. offset less than 10-20)
|
|
26
|
+
// since otherwise it won't be a markdown shortcut, but tables are exception
|
|
27
|
+
if (fromTrigger !== 'enter' && textContent[anchorOffset - 1] !== ' ') {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
var _iterator = _createForOfIteratorHelper(elementTransformers),
|
|
31
|
+
_step;
|
|
32
|
+
try {
|
|
33
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
34
|
+
var _step$value = _step.value,
|
|
35
|
+
regExp = _step$value.regExp,
|
|
36
|
+
trigger = _step$value.trigger;
|
|
37
|
+
var _match = textContent.match(regExp);
|
|
38
|
+
if (fromTrigger === trigger && _match && _match[0].length === (fromTrigger === 'enter' || _match[0].endsWith(' ') ? anchorOffset : anchorOffset - 1)) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} catch (err) {
|
|
43
|
+
_iterator.e(err);
|
|
44
|
+
} finally {
|
|
45
|
+
_iterator.f();
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
export function runElementTransformers(parentNode, anchorNode, anchorOffset, elementTransformers, fromTrigger) {
|
|
50
|
+
var grandParentNode = parentNode.getParent();
|
|
51
|
+
if (!$isRootOrShadowRoot(grandParentNode) || parentNode.getFirstChild() !== anchorNode) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
var textContent = anchorNode.getTextContent();
|
|
55
|
+
|
|
56
|
+
// Checking for anchorOffset position to prevent any checks for cases when caret is too far
|
|
57
|
+
// from a line start to be a part of block-level markdown trigger.
|
|
58
|
+
//
|
|
59
|
+
// TODO:
|
|
60
|
+
// Can have a quick check if caret is close enough to the beginning of the string (e.g. offset less than 10-20)
|
|
61
|
+
// since otherwise it won't be a markdown shortcut, but tables are exception
|
|
62
|
+
if (fromTrigger !== 'enter' && textContent[anchorOffset - 1] !== ' ') {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
var _iterator2 = _createForOfIteratorHelper(elementTransformers),
|
|
66
|
+
_step2;
|
|
67
|
+
try {
|
|
68
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
69
|
+
var _step2$value = _step2.value,
|
|
70
|
+
regExp = _step2$value.regExp,
|
|
71
|
+
replace = _step2$value.replace,
|
|
72
|
+
trigger = _step2$value.trigger;
|
|
73
|
+
var _match2 = textContent.match(regExp);
|
|
74
|
+
if (fromTrigger === trigger && _match2 && _match2[0].length === (fromTrigger === 'enter' || _match2[0].endsWith(' ') ? anchorOffset : anchorOffset - 1)) {
|
|
75
|
+
var nextSiblings = anchorNode.getNextSiblings();
|
|
76
|
+
var _anchorNode$splitText = anchorNode.splitText(anchorOffset),
|
|
77
|
+
_anchorNode$splitText2 = _slicedToArray(_anchorNode$splitText, 2),
|
|
78
|
+
leadingNode = _anchorNode$splitText2[0],
|
|
79
|
+
remainderNode = _anchorNode$splitText2[1];
|
|
80
|
+
var siblings = remainderNode ? [remainderNode].concat(_toConsumableArray(nextSiblings)) : nextSiblings;
|
|
81
|
+
if (replace(parentNode, siblings, _match2, false) !== false) {
|
|
82
|
+
leadingNode.remove();
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
} catch (err) {
|
|
88
|
+
_iterator2.e(err);
|
|
89
|
+
} finally {
|
|
90
|
+
_iterator2.f();
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
export function runTextMatchTransformers(anchorNode, anchorOffset, transformersByTrigger) {
|
|
95
|
+
var textContent = anchorNode.getTextContent();
|
|
96
|
+
var lastChar = textContent[anchorOffset - 1];
|
|
97
|
+
var transformers = transformersByTrigger[lastChar];
|
|
98
|
+
if (!transformers) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// If typing in the middle of content, remove the tail to do
|
|
103
|
+
// reg exp match up to a string end (caret position)
|
|
104
|
+
if (anchorOffset < textContent.length) {
|
|
105
|
+
textContent = textContent.slice(0, anchorOffset);
|
|
106
|
+
}
|
|
107
|
+
var _iterator3 = _createForOfIteratorHelper(transformers),
|
|
108
|
+
_step3;
|
|
109
|
+
try {
|
|
110
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
111
|
+
var transformer = _step3.value;
|
|
112
|
+
if (!transformer.replace || !transformer.regExp) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
var _match3 = textContent.match(transformer.regExp);
|
|
116
|
+
if (_match3 === null) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
var startIndex = _match3.index || 0;
|
|
120
|
+
var endIndex = startIndex + _match3[0].length;
|
|
121
|
+
var replaceNode = void 0;
|
|
122
|
+
if (startIndex === 0) {
|
|
123
|
+
var _anchorNode$splitText3 = anchorNode.splitText(endIndex);
|
|
124
|
+
var _anchorNode$splitText4 = _slicedToArray(_anchorNode$splitText3, 1);
|
|
125
|
+
replaceNode = _anchorNode$splitText4[0];
|
|
126
|
+
} else {
|
|
127
|
+
var _anchorNode$splitText5 = anchorNode.splitText(startIndex, endIndex);
|
|
128
|
+
var _anchorNode$splitText6 = _slicedToArray(_anchorNode$splitText5, 2);
|
|
129
|
+
replaceNode = _anchorNode$splitText6[1];
|
|
130
|
+
}
|
|
131
|
+
replaceNode.selectNext(0, 0);
|
|
132
|
+
transformer.replace(replaceNode, _match3);
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
} catch (err) {
|
|
136
|
+
_iterator3.e(err);
|
|
137
|
+
} finally {
|
|
138
|
+
_iterator3.f();
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
export function $runTextFormatTransformers(anchorNode, anchorOffset, textFormatTransformers) {
|
|
143
|
+
var textContent = anchorNode.getTextContent();
|
|
144
|
+
var closeTagEndIndex = anchorOffset - 1;
|
|
145
|
+
var closeChar = textContent[closeTagEndIndex];
|
|
146
|
+
// Quick check if we're possibly at the end of inline markdown style
|
|
147
|
+
var matchers = textFormatTransformers[closeChar];
|
|
148
|
+
if (!matchers) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
var _iterator4 = _createForOfIteratorHelper(matchers),
|
|
152
|
+
_step4;
|
|
153
|
+
try {
|
|
154
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
155
|
+
var matcher = _step4.value;
|
|
156
|
+
var tag = matcher.tag;
|
|
157
|
+
var tagLength = tag.length;
|
|
158
|
+
var closeTagStartIndex = closeTagEndIndex - tagLength + 1;
|
|
159
|
+
|
|
160
|
+
// If tag is not single char check if rest of it matches with text content
|
|
161
|
+
if (tagLength > 1 && !isEqualSubString(textContent, closeTagStartIndex, tag, 0, tagLength)) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Space before closing tag cancels inline markdown
|
|
166
|
+
if (textContent[closeTagStartIndex - 1] === ' ') {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Some tags can not be used within words, hence should have newline/space/punctuation after it
|
|
171
|
+
var afterCloseTagChar = textContent[closeTagEndIndex + 1];
|
|
172
|
+
if (matcher.intraword === false && afterCloseTagChar && !PUNCTUATION_OR_SPACE.test(afterCloseTagChar)) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
var closeNode = anchorNode;
|
|
176
|
+
var openNode = closeNode;
|
|
177
|
+
var openTagStartIndex = getOpenTagStartIndex(textContent, closeTagStartIndex, tag);
|
|
178
|
+
|
|
179
|
+
// Go through text node siblings and search for opening tag
|
|
180
|
+
// if haven't found it within the same text node as closing tag
|
|
181
|
+
var sibling = openNode;
|
|
182
|
+
while (openTagStartIndex < 0 && (sibling = sibling.getPreviousSibling())) {
|
|
183
|
+
if ($isLineBreakNode(sibling)) {
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
if ($isTextNode(sibling)) {
|
|
187
|
+
if (sibling.hasFormat('code')) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
var siblingTextContent = sibling.getTextContent();
|
|
191
|
+
openNode = sibling;
|
|
192
|
+
openTagStartIndex = getOpenTagStartIndex(siblingTextContent, siblingTextContent.length, tag);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Opening tag is not found
|
|
197
|
+
if (openTagStartIndex < 0) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// No content between opening and closing tag
|
|
202
|
+
if (openNode === closeNode && openTagStartIndex + tagLength === closeTagStartIndex) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Checking longer tags for repeating chars (e.g. *** vs **)
|
|
207
|
+
var prevOpenNodeText = openNode.getTextContent();
|
|
208
|
+
if (openTagStartIndex > 0 && prevOpenNodeText[openTagStartIndex - 1] === closeChar) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Some tags can not be used within words, hence should have newline/space/punctuation before it
|
|
213
|
+
var beforeOpenTagChar = prevOpenNodeText[openTagStartIndex - 1];
|
|
214
|
+
if (matcher.intraword === false && beforeOpenTagChar && !PUNCTUATION_OR_SPACE.test(beforeOpenTagChar)) {
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Clean text from opening and closing tags (starting from closing tag
|
|
219
|
+
// to prevent any offset shifts if we start from opening one)
|
|
220
|
+
var prevCloseNodeText = closeNode.getTextContent();
|
|
221
|
+
var closeNodeText = prevCloseNodeText.slice(0, closeTagStartIndex) + prevCloseNodeText.slice(closeTagEndIndex + 1);
|
|
222
|
+
closeNode.setTextContent(closeNodeText);
|
|
223
|
+
var openNodeText = openNode === closeNode ? closeNodeText : prevOpenNodeText;
|
|
224
|
+
openNode.setTextContent(openNodeText.slice(0, openTagStartIndex) + openNodeText.slice(openTagStartIndex + tagLength));
|
|
225
|
+
var _selection = $getSelection();
|
|
226
|
+
var nextSelection = $createRangeSelection();
|
|
227
|
+
$setSelection(nextSelection);
|
|
228
|
+
// Adjust offset based on deleted chars
|
|
229
|
+
var newOffset = closeTagEndIndex - tagLength * (openNode === closeNode ? 2 : 1) + 1;
|
|
230
|
+
nextSelection.anchor.set(openNode.__key, openTagStartIndex, 'text');
|
|
231
|
+
nextSelection.focus.set(closeNode.__key, newOffset, 'text');
|
|
232
|
+
if (matcher.process) {
|
|
233
|
+
matcher.process(nextSelection);
|
|
234
|
+
return true;
|
|
235
|
+
} else if (matcher.format) {
|
|
236
|
+
// Apply formatting to selected text
|
|
237
|
+
var _iterator5 = _createForOfIteratorHelper(matcher.format),
|
|
238
|
+
_step5;
|
|
239
|
+
try {
|
|
240
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
241
|
+
var format = _step5.value;
|
|
242
|
+
if (!nextSelection.hasFormat(format)) {
|
|
243
|
+
nextSelection.formatText(format);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Collapse selection up to the focus point
|
|
248
|
+
} catch (err) {
|
|
249
|
+
_iterator5.e(err);
|
|
250
|
+
} finally {
|
|
251
|
+
_iterator5.f();
|
|
252
|
+
}
|
|
253
|
+
nextSelection.anchor.set(nextSelection.focus.key, nextSelection.focus.offset, nextSelection.focus.type);
|
|
254
|
+
|
|
255
|
+
// Remove formatting from collapsed selection
|
|
256
|
+
var _iterator6 = _createForOfIteratorHelper(matcher.format),
|
|
257
|
+
_step6;
|
|
258
|
+
try {
|
|
259
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
260
|
+
var _format = _step6.value;
|
|
261
|
+
if (nextSelection.hasFormat(_format)) {
|
|
262
|
+
nextSelection.toggleFormat(_format);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
} catch (err) {
|
|
266
|
+
_iterator6.e(err);
|
|
267
|
+
} finally {
|
|
268
|
+
_iterator6.f();
|
|
269
|
+
}
|
|
270
|
+
if ($isRangeSelection(_selection)) {
|
|
271
|
+
nextSelection.format = _selection.format;
|
|
272
|
+
}
|
|
273
|
+
} else {
|
|
274
|
+
// No format or process specified, nothing to do
|
|
275
|
+
$setSelection(_selection);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
return true;
|
|
279
|
+
}
|
|
280
|
+
} catch (err) {
|
|
281
|
+
_iterator4.e(err);
|
|
282
|
+
} finally {
|
|
283
|
+
_iterator4.f();
|
|
284
|
+
}
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LexicalNode, TextNode } from 'lexical';
|
|
1
|
+
import { BaseSelection, LexicalEditor, LexicalNode, TextNode } from 'lexical';
|
|
2
2
|
/**
|
|
3
3
|
* Returns true if the node can contain transformable markdown.
|
|
4
4
|
* Code nodes cannot contain transformable markdown.
|
|
@@ -16,3 +16,47 @@ export declare function indexBy<T>(list: Array<T>, callback: (arg0: T) => string
|
|
|
16
16
|
* @returns True if the character is a punctuation character, false otherwise.
|
|
17
17
|
*/
|
|
18
18
|
export declare function isPunctuationChar(char: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Inserts Lexical nodes into the editor using different strategies depending on
|
|
21
|
+
* some simple selection-based heuristics. If you're looking for a generic way to
|
|
22
|
+
* to insert nodes into the editor at a specific selection point, you probably want
|
|
23
|
+
* {@link lexical.$insertNodes}
|
|
24
|
+
*
|
|
25
|
+
* @param editor LexicalEditor instance to insert the nodes into.
|
|
26
|
+
* @param nodes The nodes to insert.
|
|
27
|
+
* @param selection The selection to insert the nodes into.
|
|
28
|
+
*/
|
|
29
|
+
export declare function $insertGeneratedNodes(editor: LexicalEditor, nodes: Array<LexicalNode>, selection: BaseSelection): void;
|
|
30
|
+
export interface BaseSerializedNode {
|
|
31
|
+
children?: Array<BaseSerializedNode>;
|
|
32
|
+
type: string;
|
|
33
|
+
version: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates an object containing all the styles and their values provided in the CSS string.
|
|
37
|
+
* @param css - The CSS string of styles and their values.
|
|
38
|
+
* @returns The styleObject containing all the styles and their values.
|
|
39
|
+
*/
|
|
40
|
+
export declare function getStyleObjectFromRawCSS(css: string): Record<string, string>;
|
|
41
|
+
/**
|
|
42
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
43
|
+
*
|
|
44
|
+
* This source code is licensed under the MIT license found in the
|
|
45
|
+
* LICENSE file in the root directory of this source tree.
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
export declare const CSS_TO_STYLES: Map<string, Record<string, string>>;
|
|
49
|
+
/**
|
|
50
|
+
* Gets the TextNode's style object and adds the styles to the CSS.
|
|
51
|
+
* @param node - The TextNode to add styles to.
|
|
52
|
+
*/
|
|
53
|
+
export declare function $addNodeStyle(node: TextNode): void;
|
|
54
|
+
/**
|
|
55
|
+
* This method takes an array of objects conforming to the BaseSerializedNode interface and returns
|
|
56
|
+
* an Array containing instances of the corresponding LexicalNode classes registered on the editor.
|
|
57
|
+
* Normally, you'd get an Array of BaseSerialized nodes from {@link $generateJSONFromSelectedNodes}
|
|
58
|
+
*
|
|
59
|
+
* @param serializedNodes an Array of objects conforming to the BaseSerializedNode interface.
|
|
60
|
+
* @returns an Array of Lexical Node objects.
|
|
61
|
+
*/
|
|
62
|
+
export declare function $generateNodesFromSerializedNodes(serializedNodes: Array<BaseSerializedNode>): Array<LexicalNode>;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
2
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
4
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
1
5
|
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; } } }; }
|
|
2
6
|
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); }
|
|
3
7
|
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; }
|
|
4
|
-
import { $isTextNode } from 'lexical';
|
|
8
|
+
import { $caretFromPoint, $getCaretRange, $getChildCaret, $getRoot, $isElementNode, $isRangeSelection, $isTextNode, $isTextPointCaret, $parseSerializedNode, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND } from 'lexical';
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Returns true if the node can contain transformable markdown.
|
|
@@ -71,4 +75,146 @@ try {
|
|
|
71
75
|
*/
|
|
72
76
|
export function isPunctuationChar(char) {
|
|
73
77
|
return Punctuation.test(char);
|
|
78
|
+
}
|
|
79
|
+
function $updateSelectionOnInsert(selection) {
|
|
80
|
+
if ($isRangeSelection(selection) && selection.isCollapsed()) {
|
|
81
|
+
var anchor = selection.anchor;
|
|
82
|
+
var nodeToInspect = null;
|
|
83
|
+
var anchorCaret = $caretFromPoint(anchor, 'previous');
|
|
84
|
+
if (anchorCaret) {
|
|
85
|
+
if ($isTextPointCaret(anchorCaret)) {
|
|
86
|
+
nodeToInspect = anchorCaret.origin;
|
|
87
|
+
} else {
|
|
88
|
+
var range = $getCaretRange(anchorCaret, $getChildCaret($getRoot(), 'next').getFlipped());
|
|
89
|
+
var _iterator2 = _createForOfIteratorHelper(range),
|
|
90
|
+
_step2;
|
|
91
|
+
try {
|
|
92
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
93
|
+
var caret = _step2.value;
|
|
94
|
+
if ($isTextNode(caret.origin)) {
|
|
95
|
+
nodeToInspect = caret.origin;
|
|
96
|
+
break;
|
|
97
|
+
} else if ($isElementNode(caret.origin) && !caret.origin.isInline()) {
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} catch (err) {
|
|
102
|
+
_iterator2.e(err);
|
|
103
|
+
} finally {
|
|
104
|
+
_iterator2.f();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (nodeToInspect && $isTextNode(nodeToInspect)) {
|
|
109
|
+
var newFormat = nodeToInspect.getFormat();
|
|
110
|
+
var newStyle = nodeToInspect.getStyle();
|
|
111
|
+
if (selection.format !== newFormat || selection.style !== newStyle) {
|
|
112
|
+
selection.format = newFormat;
|
|
113
|
+
selection.style = newStyle;
|
|
114
|
+
selection.dirty = true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Inserts Lexical nodes into the editor using different strategies depending on
|
|
122
|
+
* some simple selection-based heuristics. If you're looking for a generic way to
|
|
123
|
+
* to insert nodes into the editor at a specific selection point, you probably want
|
|
124
|
+
* {@link lexical.$insertNodes}
|
|
125
|
+
*
|
|
126
|
+
* @param editor LexicalEditor instance to insert the nodes into.
|
|
127
|
+
* @param nodes The nodes to insert.
|
|
128
|
+
* @param selection The selection to insert the nodes into.
|
|
129
|
+
*/
|
|
130
|
+
export function $insertGeneratedNodes(editor, nodes, selection) {
|
|
131
|
+
if (!editor.dispatchCommand(SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, {
|
|
132
|
+
nodes: nodes,
|
|
133
|
+
selection: selection
|
|
134
|
+
})) {
|
|
135
|
+
selection.insertNodes(nodes);
|
|
136
|
+
$updateSelectionOnInsert(selection);
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Creates an object containing all the styles and their values provided in the CSS string.
|
|
142
|
+
* @param css - The CSS string of styles and their values.
|
|
143
|
+
* @returns The styleObject containing all the styles and their values.
|
|
144
|
+
*/
|
|
145
|
+
export function getStyleObjectFromRawCSS(css) {
|
|
146
|
+
var styleObject = {};
|
|
147
|
+
if (!css) {
|
|
148
|
+
return styleObject;
|
|
149
|
+
}
|
|
150
|
+
var styles = css.split(';');
|
|
151
|
+
var _iterator3 = _createForOfIteratorHelper(styles),
|
|
152
|
+
_step3;
|
|
153
|
+
try {
|
|
154
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
155
|
+
var style = _step3.value;
|
|
156
|
+
if (style !== '') {
|
|
157
|
+
var _style$split = style.split(/:([^]+)/),
|
|
158
|
+
_style$split2 = _slicedToArray(_style$split, 2),
|
|
159
|
+
key = _style$split2[0],
|
|
160
|
+
value = _style$split2[1]; // split on first colon
|
|
161
|
+
if (key && value) {
|
|
162
|
+
styleObject[key.trim()] = value.trim();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
} catch (err) {
|
|
167
|
+
_iterator3.e(err);
|
|
168
|
+
} finally {
|
|
169
|
+
_iterator3.f();
|
|
170
|
+
}
|
|
171
|
+
return styleObject;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
176
|
+
*
|
|
177
|
+
* This source code is licensed under the MIT license found in the
|
|
178
|
+
* LICENSE file in the root directory of this source tree.
|
|
179
|
+
*
|
|
180
|
+
*/
|
|
181
|
+
export var CSS_TO_STYLES = new Map();
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Gets the TextNode's style object and adds the styles to the CSS.
|
|
185
|
+
* @param node - The TextNode to add styles to.
|
|
186
|
+
*/
|
|
187
|
+
export function $addNodeStyle(node) {
|
|
188
|
+
var CSSText = node.getStyle();
|
|
189
|
+
var styles = getStyleObjectFromRawCSS(CSSText);
|
|
190
|
+
CSS_TO_STYLES.set(CSSText, styles);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* This method takes an array of objects conforming to the BaseSerializedNode interface and returns
|
|
195
|
+
* an Array containing instances of the corresponding LexicalNode classes registered on the editor.
|
|
196
|
+
* Normally, you'd get an Array of BaseSerialized nodes from {@link $generateJSONFromSelectedNodes}
|
|
197
|
+
*
|
|
198
|
+
* @param serializedNodes an Array of objects conforming to the BaseSerializedNode interface.
|
|
199
|
+
* @returns an Array of Lexical Node objects.
|
|
200
|
+
*/
|
|
201
|
+
export function $generateNodesFromSerializedNodes(serializedNodes) {
|
|
202
|
+
var nodes = [];
|
|
203
|
+
var _iterator4 = _createForOfIteratorHelper(serializedNodes),
|
|
204
|
+
_step4;
|
|
205
|
+
try {
|
|
206
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
207
|
+
var serializedNode = _step4.value;
|
|
208
|
+
var node = $parseSerializedNode(serializedNode);
|
|
209
|
+
if ($isTextNode(node)) {
|
|
210
|
+
$addNodeStyle(node);
|
|
211
|
+
}
|
|
212
|
+
nodes.push(node);
|
|
213
|
+
}
|
|
214
|
+
} catch (err) {
|
|
215
|
+
_iterator4.e(err);
|
|
216
|
+
} finally {
|
|
217
|
+
_iterator4.f();
|
|
218
|
+
}
|
|
219
|
+
return nodes;
|
|
74
220
|
}
|
|
@@ -20,6 +20,7 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
|
|
|
20
20
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
21
21
|
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); }
|
|
22
22
|
import { $createNodeSelection, $setSelection } from 'lexical';
|
|
23
|
+
import { INodeHelper } from "../../../editor-kernel/inode/helper";
|
|
23
24
|
import { KernelPlugin } from "../../../editor-kernel/plugin";
|
|
24
25
|
import { IMarkdownShortCutService } from "../../markdown";
|
|
25
26
|
import { createDebugLogger } from "../../../utils/debug";
|
|
@@ -32,7 +33,6 @@ export var MathPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
|
|
|
32
33
|
_inherits(MathPlugin, _KernelPlugin);
|
|
33
34
|
var _super = _createSuper(MathPlugin);
|
|
34
35
|
function MathPlugin(kernel, config) {
|
|
35
|
-
var _kernel$requireServic, _kernel$requireServic2, _kernel$requireServic3, _kernel$requireServic4;
|
|
36
36
|
var _this;
|
|
37
37
|
_classCallCheck(this, MathPlugin);
|
|
38
38
|
_this = _super.call(this);
|
|
@@ -49,56 +49,75 @@ export var MathPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
|
|
|
49
49
|
_this.registerDecorator(kernel, MathBlockNode.getType(), function (node, editor) {
|
|
50
50
|
return config !== null && config !== void 0 && config.decorator ? config.decorator(node, editor) : null;
|
|
51
51
|
});
|
|
52
|
-
(_kernel$requireServic = kernel.requireService(IMarkdownShortCutService)) === null || _kernel$requireServic === void 0 || _kernel$requireServic.registerMarkdownShortCut({
|
|
53
|
-
regExp: /\$([^$]+)\$\s?$/,
|
|
54
|
-
replace: function replace(textNode, match) {
|
|
55
|
-
var _match = _slicedToArray(match, 2),
|
|
56
|
-
code = _match[1];
|
|
57
|
-
var mathNode = $createMathInlineNode(code);
|
|
58
|
-
_this.logger.debug('Math node inserted:', mathNode);
|
|
59
|
-
// textNode.replace(mathNode);
|
|
60
|
-
textNode.insertBefore(mathNode);
|
|
61
|
-
textNode.setTextContent('');
|
|
62
|
-
textNode.select();
|
|
63
|
-
// mathNode.selectEnd();
|
|
64
|
-
|
|
65
|
-
return;
|
|
66
|
-
},
|
|
67
|
-
trigger: '$',
|
|
68
|
-
type: 'text-match'
|
|
69
|
-
});
|
|
70
|
-
(_kernel$requireServic2 = kernel.requireService(IMarkdownShortCutService)) === null || _kernel$requireServic2 === void 0 || _kernel$requireServic2.registerMarkdownShortCut({
|
|
71
|
-
regExp: /^(\$\$)$/,
|
|
72
|
-
replace: function replace(parentNode, _1, _2, isImport) {
|
|
73
|
-
var node = $createMathBlockNode();
|
|
74
|
-
|
|
75
|
-
// TODO: Get rid of isImport flag
|
|
76
|
-
if (isImport || parentNode.getNextSibling()) {
|
|
77
|
-
parentNode.replace(node);
|
|
78
|
-
} else {
|
|
79
|
-
parentNode.insertBefore(node);
|
|
80
|
-
}
|
|
81
|
-
var sel = $createNodeSelection();
|
|
82
|
-
sel.add(node.getKey());
|
|
83
|
-
$setSelection(sel);
|
|
84
|
-
},
|
|
85
|
-
trigger: 'enter',
|
|
86
|
-
type: 'element'
|
|
87
|
-
});
|
|
88
|
-
(_kernel$requireServic3 = kernel.requireService(IMarkdownShortCutService)) === null || _kernel$requireServic3 === void 0 || _kernel$requireServic3.registerMarkdownWriter(MathInlineNode.getType(), function (ctx, node) {
|
|
89
|
-
ctx.appendLine(node.getTextContent());
|
|
90
|
-
return true;
|
|
91
|
-
});
|
|
92
|
-
(_kernel$requireServic4 = kernel.requireService(IMarkdownShortCutService)) === null || _kernel$requireServic4 === void 0 || _kernel$requireServic4.registerMarkdownWriter(MathBlockNode.getType(), function (ctx, node) {
|
|
93
|
-
ctx.appendLine(node.getTextContent());
|
|
94
|
-
return true;
|
|
95
|
-
});
|
|
96
52
|
return _this;
|
|
97
53
|
}
|
|
98
54
|
_createClass(MathPlugin, [{
|
|
99
55
|
key: "onInit",
|
|
100
56
|
value: function onInit(editor) {
|
|
101
57
|
this.register(registerMathCommand(editor));
|
|
58
|
+
this.registerMarkdown();
|
|
59
|
+
}
|
|
60
|
+
}, {
|
|
61
|
+
key: "registerMarkdown",
|
|
62
|
+
value: function registerMarkdown() {
|
|
63
|
+
var _this2 = this;
|
|
64
|
+
var markdownService = this.kernel.requireService(IMarkdownShortCutService);
|
|
65
|
+
markdownService === null || markdownService === void 0 || markdownService.registerMarkdownShortCut({
|
|
66
|
+
regExp: /\$([^$]+)\$\s?$/,
|
|
67
|
+
replace: function replace(textNode, match) {
|
|
68
|
+
var _match = _slicedToArray(match, 2),
|
|
69
|
+
code = _match[1];
|
|
70
|
+
var mathNode = $createMathInlineNode(code);
|
|
71
|
+
_this2.logger.debug('Math node inserted:', mathNode);
|
|
72
|
+
// textNode.replace(mathNode);
|
|
73
|
+
textNode.insertBefore(mathNode);
|
|
74
|
+
textNode.setTextContent('');
|
|
75
|
+
textNode.select();
|
|
76
|
+
// mathNode.selectEnd();
|
|
77
|
+
|
|
78
|
+
return;
|
|
79
|
+
},
|
|
80
|
+
trigger: '$',
|
|
81
|
+
type: 'text-match'
|
|
82
|
+
});
|
|
83
|
+
markdownService === null || markdownService === void 0 || markdownService.registerMarkdownShortCut({
|
|
84
|
+
regExp: /^(\$\$)$/,
|
|
85
|
+
replace: function replace(parentNode, _1, _2, isImport) {
|
|
86
|
+
var node = $createMathBlockNode();
|
|
87
|
+
|
|
88
|
+
// TODO: Get rid of isImport flag
|
|
89
|
+
if (isImport || parentNode.getNextSibling()) {
|
|
90
|
+
parentNode.replace(node);
|
|
91
|
+
} else {
|
|
92
|
+
parentNode.insertBefore(node);
|
|
93
|
+
}
|
|
94
|
+
var sel = $createNodeSelection();
|
|
95
|
+
sel.add(node.getKey());
|
|
96
|
+
$setSelection(sel);
|
|
97
|
+
},
|
|
98
|
+
trigger: 'enter',
|
|
99
|
+
type: 'element'
|
|
100
|
+
});
|
|
101
|
+
markdownService === null || markdownService === void 0 || markdownService.registerMarkdownWriter(MathInlineNode.getType(), function (ctx, node) {
|
|
102
|
+
ctx.appendLine(node.getTextContent());
|
|
103
|
+
return true;
|
|
104
|
+
});
|
|
105
|
+
markdownService === null || markdownService === void 0 || markdownService.registerMarkdownWriter(MathBlockNode.getType(), function (ctx, node) {
|
|
106
|
+
ctx.appendLine(node.getTextContent());
|
|
107
|
+
return true;
|
|
108
|
+
});
|
|
109
|
+
markdownService === null || markdownService === void 0 || markdownService.registerMarkdownReader('inlineMath', function (node) {
|
|
110
|
+
return INodeHelper.createElementNode('math', {
|
|
111
|
+
code: node.value,
|
|
112
|
+
version: 1
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
markdownService === null || markdownService === void 0 || markdownService.registerMarkdownReader('math', function (node) {
|
|
116
|
+
return INodeHelper.createElementNode('mathBlock', {
|
|
117
|
+
code: node.value,
|
|
118
|
+
version: 1
|
|
119
|
+
});
|
|
120
|
+
});
|
|
102
121
|
}
|
|
103
122
|
}]);
|
|
104
123
|
return MathPlugin;
|