@lexical/markdown 0.12.1 → 0.12.3
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/LexicalMarkdown.dev.js +90 -222
- package/LexicalMarkdown.prod.js +9 -9
- package/package.json +8 -8
package/LexicalMarkdown.dev.js
CHANGED
|
@@ -20,20 +20,16 @@ var link = require('@lexical/link');
|
|
|
20
20
|
* LICENSE file in the root directory of this source tree.
|
|
21
21
|
*
|
|
22
22
|
*/
|
|
23
|
-
|
|
24
23
|
function indexBy(list, callback) {
|
|
25
24
|
const index = {};
|
|
26
|
-
|
|
27
25
|
for (const item of list) {
|
|
28
26
|
const key = callback(item);
|
|
29
|
-
|
|
30
27
|
if (index[key]) {
|
|
31
28
|
index[key].push(item);
|
|
32
29
|
} else {
|
|
33
30
|
index[key] = [item];
|
|
34
31
|
}
|
|
35
32
|
}
|
|
36
|
-
|
|
37
33
|
return index;
|
|
38
34
|
}
|
|
39
35
|
function transformersByType(transformers) {
|
|
@@ -54,35 +50,30 @@ const PUNCTUATION_OR_SPACE = /[!-/:-@[-`{-~\s]/;
|
|
|
54
50
|
*
|
|
55
51
|
*/
|
|
56
52
|
function createMarkdownExport(transformers) {
|
|
57
|
-
const byType = transformersByType(transformers);
|
|
58
|
-
// e.g. it will filter out *** (bold, italic) and instead use separate ** and *
|
|
53
|
+
const byType = transformersByType(transformers);
|
|
59
54
|
|
|
55
|
+
// Export only uses text formats that are responsible for single format
|
|
56
|
+
// e.g. it will filter out *** (bold, italic) and instead use separate ** and *
|
|
60
57
|
const textFormatTransformers = byType.textFormat.filter(transformer => transformer.format.length === 1);
|
|
61
58
|
return node => {
|
|
62
59
|
const output = [];
|
|
63
60
|
const children = (node || lexical.$getRoot()).getChildren();
|
|
64
|
-
|
|
65
61
|
for (const child of children) {
|
|
66
62
|
const result = exportTopLevelElements(child, byType.element, textFormatTransformers, byType.textMatch);
|
|
67
|
-
|
|
68
63
|
if (result != null) {
|
|
69
64
|
output.push(result);
|
|
70
65
|
}
|
|
71
66
|
}
|
|
72
|
-
|
|
73
67
|
return output.join('\n\n');
|
|
74
68
|
};
|
|
75
69
|
}
|
|
76
|
-
|
|
77
70
|
function exportTopLevelElements(node, elementTransformers, textTransformersIndex, textMatchTransformers) {
|
|
78
71
|
for (const transformer of elementTransformers) {
|
|
79
72
|
const result = transformer.export(node, _node => exportChildren(_node, textTransformersIndex, textMatchTransformers));
|
|
80
|
-
|
|
81
73
|
if (result != null) {
|
|
82
74
|
return result;
|
|
83
75
|
}
|
|
84
76
|
}
|
|
85
|
-
|
|
86
77
|
if (lexical.$isElementNode(node)) {
|
|
87
78
|
return exportChildren(node, textTransformersIndex, textMatchTransformers);
|
|
88
79
|
} else if (lexical.$isDecoratorNode(node)) {
|
|
@@ -91,21 +82,17 @@ function exportTopLevelElements(node, elementTransformers, textTransformersIndex
|
|
|
91
82
|
return null;
|
|
92
83
|
}
|
|
93
84
|
}
|
|
94
|
-
|
|
95
85
|
function exportChildren(node, textTransformersIndex, textMatchTransformers) {
|
|
96
86
|
const output = [];
|
|
97
87
|
const children = node.getChildren();
|
|
98
|
-
|
|
99
88
|
mainLoop: for (const child of children) {
|
|
100
89
|
for (const transformer of textMatchTransformers) {
|
|
101
90
|
const result = transformer.export(child, parentNode => exportChildren(parentNode, textTransformersIndex, textMatchTransformers), (textNode, textContent) => exportTextFormat(textNode, textContent, textTransformersIndex));
|
|
102
|
-
|
|
103
91
|
if (result != null) {
|
|
104
92
|
output.push(result);
|
|
105
93
|
continue mainLoop;
|
|
106
94
|
}
|
|
107
95
|
}
|
|
108
|
-
|
|
109
96
|
if (lexical.$isLineBreakNode(child)) {
|
|
110
97
|
output.push('\n');
|
|
111
98
|
} else if (lexical.$isTextNode(child)) {
|
|
@@ -116,10 +103,8 @@ function exportChildren(node, textTransformersIndex, textMatchTransformers) {
|
|
|
116
103
|
output.push(child.getTextContent());
|
|
117
104
|
}
|
|
118
105
|
}
|
|
119
|
-
|
|
120
106
|
return output.join('');
|
|
121
107
|
}
|
|
122
|
-
|
|
123
108
|
function exportTextFormat(node, textContent, textTransformers) {
|
|
124
109
|
// This function handles the case of a string looking like this: " foo "
|
|
125
110
|
// Where it would be invalid markdown to generate: "** foo **"
|
|
@@ -128,74 +113,61 @@ function exportTextFormat(node, textContent, textTransformers) {
|
|
|
128
113
|
const frozenString = textContent.trim();
|
|
129
114
|
let output = frozenString;
|
|
130
115
|
const applied = new Set();
|
|
131
|
-
|
|
132
116
|
for (const transformer of textTransformers) {
|
|
133
117
|
const format = transformer.format[0];
|
|
134
118
|
const tag = transformer.tag;
|
|
135
|
-
|
|
136
119
|
if (hasFormat(node, format) && !applied.has(format)) {
|
|
137
120
|
// Multiple tags might be used for the same format (*, _)
|
|
138
|
-
applied.add(format);
|
|
139
|
-
|
|
121
|
+
applied.add(format);
|
|
122
|
+
// Prevent adding opening tag is already opened by the previous sibling
|
|
140
123
|
const previousNode = getTextSibling(node, true);
|
|
141
|
-
|
|
142
124
|
if (!hasFormat(previousNode, format)) {
|
|
143
125
|
output = tag + output;
|
|
144
|
-
}
|
|
145
|
-
|
|
126
|
+
}
|
|
146
127
|
|
|
128
|
+
// Prevent adding closing tag if next sibling will do it
|
|
147
129
|
const nextNode = getTextSibling(node, false);
|
|
148
|
-
|
|
149
130
|
if (!hasFormat(nextNode, format)) {
|
|
150
131
|
output += tag;
|
|
151
132
|
}
|
|
152
133
|
}
|
|
153
|
-
}
|
|
154
|
-
|
|
134
|
+
}
|
|
155
135
|
|
|
136
|
+
// Replace trimmed version of textContent ensuring surrounding whitespace is not modified
|
|
156
137
|
return textContent.replace(frozenString, output);
|
|
157
|
-
}
|
|
158
|
-
// when it's a child of inline element (e.g. link)
|
|
159
|
-
|
|
138
|
+
}
|
|
160
139
|
|
|
140
|
+
// Get next or previous text sibling a text node, including cases
|
|
141
|
+
// when it's a child of inline element (e.g. link)
|
|
161
142
|
function getTextSibling(node, backward) {
|
|
162
143
|
let sibling = backward ? node.getPreviousSibling() : node.getNextSibling();
|
|
163
|
-
|
|
164
144
|
if (!sibling) {
|
|
165
145
|
const parent = node.getParentOrThrow();
|
|
166
|
-
|
|
167
146
|
if (parent.isInline()) {
|
|
168
147
|
sibling = backward ? parent.getPreviousSibling() : parent.getNextSibling();
|
|
169
148
|
}
|
|
170
149
|
}
|
|
171
|
-
|
|
172
150
|
while (sibling) {
|
|
173
151
|
if (lexical.$isElementNode(sibling)) {
|
|
174
152
|
if (!sibling.isInline()) {
|
|
175
153
|
break;
|
|
176
154
|
}
|
|
177
|
-
|
|
178
155
|
const descendant = backward ? sibling.getLastDescendant() : sibling.getFirstDescendant();
|
|
179
|
-
|
|
180
156
|
if (lexical.$isTextNode(descendant)) {
|
|
181
157
|
return descendant;
|
|
182
158
|
} else {
|
|
183
159
|
sibling = backward ? sibling.getPreviousSibling() : sibling.getNextSibling();
|
|
184
160
|
}
|
|
185
161
|
}
|
|
186
|
-
|
|
187
162
|
if (lexical.$isTextNode(sibling)) {
|
|
188
163
|
return sibling;
|
|
189
164
|
}
|
|
190
|
-
|
|
191
165
|
if (!lexical.$isElementNode(sibling)) {
|
|
192
166
|
return null;
|
|
193
167
|
}
|
|
194
168
|
}
|
|
195
|
-
|
|
196
169
|
return null;
|
|
197
170
|
}
|
|
198
|
-
|
|
199
171
|
function hasFormat(node, format) {
|
|
200
172
|
return lexical.$isTextNode(node) && node.hasFormat(format);
|
|
201
173
|
}
|
|
@@ -207,6 +179,7 @@ function hasFormat(node, format) {
|
|
|
207
179
|
* LICENSE file in the root directory of this source tree.
|
|
208
180
|
*
|
|
209
181
|
*/
|
|
182
|
+
|
|
210
183
|
const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
211
184
|
|
|
212
185
|
/**
|
|
@@ -221,10 +194,13 @@ CAN_USE_DOM && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
|
|
|
221
194
|
CAN_USE_DOM && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
|
|
222
195
|
CAN_USE_DOM && 'InputEvent' in window && !documentMode ? 'getTargetRanges' in new window.InputEvent('input') : false;
|
|
223
196
|
const IS_SAFARI = CAN_USE_DOM && /Version\/[\d.]+.*Safari/.test(navigator.userAgent);
|
|
224
|
-
const IS_IOS = CAN_USE_DOM && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
|
|
225
|
-
|
|
197
|
+
const IS_IOS = CAN_USE_DOM && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
|
|
198
|
+
CAN_USE_DOM && /Android/.test(navigator.userAgent);
|
|
226
199
|
|
|
227
|
-
|
|
200
|
+
// Keep these in case we need to use them in the future.
|
|
201
|
+
// export const IS_WINDOWS: boolean = CAN_USE_DOM && /Win/.test(navigator.platform);
|
|
202
|
+
const IS_CHROME = CAN_USE_DOM && /^(?=.*Chrome).*/i.test(navigator.userAgent);
|
|
203
|
+
// export const canUseTextInputEvent: boolean = CAN_USE_DOM && 'TextEvent' in window && !documentMode;
|
|
228
204
|
|
|
229
205
|
const IS_APPLE_WEBKIT = CAN_USE_DOM && /AppleWebKit\/[\d.]+/.test(navigator.userAgent) && !IS_CHROME;
|
|
230
206
|
|
|
@@ -245,88 +221,74 @@ function createMarkdownImport(transformers) {
|
|
|
245
221
|
const linesLength = lines.length;
|
|
246
222
|
const root = node || lexical.$getRoot();
|
|
247
223
|
root.clear();
|
|
248
|
-
|
|
249
224
|
for (let i = 0; i < linesLength; i++) {
|
|
250
|
-
const lineText = lines[i];
|
|
225
|
+
const lineText = lines[i];
|
|
226
|
+
// Codeblocks are processed first as anything inside such block
|
|
251
227
|
// is ignored for further processing
|
|
252
228
|
// TODO:
|
|
253
229
|
// Abstract it to be dynamic as other transformers (add multiline match option)
|
|
254
|
-
|
|
255
230
|
const [codeBlockNode, shiftedIndex] = importCodeBlock(lines, i, root);
|
|
256
|
-
|
|
257
231
|
if (codeBlockNode != null) {
|
|
258
232
|
i = shiftedIndex;
|
|
259
233
|
continue;
|
|
260
234
|
}
|
|
261
|
-
|
|
262
235
|
importBlocks(lineText, root, byType.element, textFormatTransformersIndex, byType.textMatch);
|
|
263
|
-
}
|
|
264
|
-
// allow empty lines and uses them as dilimiter
|
|
265
|
-
|
|
236
|
+
}
|
|
266
237
|
|
|
238
|
+
// Removing empty paragraphs as md does not really
|
|
239
|
+
// allow empty lines and uses them as dilimiter
|
|
267
240
|
const children = root.getChildren();
|
|
268
|
-
|
|
269
241
|
for (const child of children) {
|
|
270
242
|
if (isEmptyParagraph(child)) {
|
|
271
243
|
child.remove();
|
|
272
244
|
}
|
|
273
245
|
}
|
|
274
|
-
|
|
275
246
|
if (lexical.$getSelection() !== null) {
|
|
276
247
|
root.selectEnd();
|
|
277
248
|
}
|
|
278
249
|
};
|
|
279
250
|
}
|
|
280
|
-
|
|
281
251
|
function isEmptyParagraph(node) {
|
|
282
252
|
if (!lexical.$isParagraphNode(node)) {
|
|
283
253
|
return false;
|
|
284
254
|
}
|
|
285
|
-
|
|
286
255
|
const firstChild = node.getFirstChild();
|
|
287
256
|
return firstChild == null || node.getChildrenSize() === 1 && lexical.$isTextNode(firstChild) && MARKDOWN_EMPTY_LINE_REG_EXP.test(firstChild.getTextContent());
|
|
288
257
|
}
|
|
289
|
-
|
|
290
258
|
function importBlocks(lineText, rootNode, elementTransformers, textFormatTransformersIndex, textMatchTransformers) {
|
|
291
259
|
const lineTextTrimmed = lineText.trim();
|
|
292
260
|
const textNode = lexical.$createTextNode(lineTextTrimmed);
|
|
293
261
|
const elementNode = lexical.$createParagraphNode();
|
|
294
262
|
elementNode.append(textNode);
|
|
295
263
|
rootNode.append(elementNode);
|
|
296
|
-
|
|
297
264
|
for (const {
|
|
298
265
|
regExp,
|
|
299
266
|
replace
|
|
300
267
|
} of elementTransformers) {
|
|
301
268
|
const match = lineText.match(regExp);
|
|
302
|
-
|
|
303
269
|
if (match) {
|
|
304
270
|
textNode.setTextContent(lineText.slice(match[0].length));
|
|
305
271
|
replace(elementNode, [textNode], match, true);
|
|
306
272
|
break;
|
|
307
273
|
}
|
|
308
274
|
}
|
|
275
|
+
importTextFormatTransformers(textNode, textFormatTransformersIndex, textMatchTransformers);
|
|
309
276
|
|
|
310
|
-
|
|
277
|
+
// If no transformer found and we left with original paragraph node
|
|
311
278
|
// can check if its content can be appended to the previous node
|
|
312
279
|
// if it's a paragraph, quote or list
|
|
313
|
-
|
|
314
280
|
if (elementNode.isAttached() && lineTextTrimmed.length > 0) {
|
|
315
281
|
const previousNode = elementNode.getPreviousSibling();
|
|
316
|
-
|
|
317
282
|
if (lexical.$isParagraphNode(previousNode) || richText.$isQuoteNode(previousNode) || list.$isListNode(previousNode)) {
|
|
318
283
|
let targetNode = previousNode;
|
|
319
|
-
|
|
320
284
|
if (list.$isListNode(previousNode)) {
|
|
321
285
|
const lastDescendant = previousNode.getLastDescendant();
|
|
322
|
-
|
|
323
286
|
if (lastDescendant == null) {
|
|
324
287
|
targetNode = null;
|
|
325
288
|
} else {
|
|
326
289
|
targetNode = utils.$findMatchingParent(lastDescendant, list.$isListItemNode);
|
|
327
290
|
}
|
|
328
291
|
}
|
|
329
|
-
|
|
330
292
|
if (targetNode != null && targetNode.getTextContentSize() > 0) {
|
|
331
293
|
targetNode.splice(targetNode.getChildrenSize(), 0, [lexical.$createLineBreakNode(), ...elementNode.getChildren()]);
|
|
332
294
|
elementNode.remove();
|
|
@@ -334,17 +296,13 @@ function importBlocks(lineText, rootNode, elementTransformers, textFormatTransfo
|
|
|
334
296
|
}
|
|
335
297
|
}
|
|
336
298
|
}
|
|
337
|
-
|
|
338
299
|
function importCodeBlock(lines, startLineIndex, rootNode) {
|
|
339
300
|
const openMatch = lines[startLineIndex].match(CODE_BLOCK_REG_EXP);
|
|
340
|
-
|
|
341
301
|
if (openMatch) {
|
|
342
302
|
let endLineIndex = startLineIndex;
|
|
343
303
|
const linesLength = lines.length;
|
|
344
|
-
|
|
345
304
|
while (++endLineIndex < linesLength) {
|
|
346
305
|
const closeMatch = lines[endLineIndex].match(CODE_BLOCK_REG_EXP);
|
|
347
|
-
|
|
348
306
|
if (closeMatch) {
|
|
349
307
|
const codeBlockNode = code.$createCodeNode(openMatch[1]);
|
|
350
308
|
const textNode = lexical.$createTextNode(lines.slice(startLineIndex + 1, endLineIndex).join('\n'));
|
|
@@ -354,157 +312,133 @@ function importCodeBlock(lines, startLineIndex, rootNode) {
|
|
|
354
312
|
}
|
|
355
313
|
}
|
|
356
314
|
}
|
|
357
|
-
|
|
358
315
|
return [null, startLineIndex];
|
|
359
|
-
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Processing text content and replaces text format tags.
|
|
360
319
|
// It takes outermost tag match and its content, creates text node with
|
|
361
320
|
// format based on tag and then recursively executed over node's content
|
|
362
321
|
//
|
|
363
322
|
// E.g. for "*Hello **world**!*" string it will create text node with
|
|
364
323
|
// "Hello **world**!" content and italic format and run recursively over
|
|
365
324
|
// its content to transform "**world**" part
|
|
366
|
-
|
|
367
|
-
|
|
368
325
|
function importTextFormatTransformers(textNode, textFormatTransformersIndex, textMatchTransformers) {
|
|
369
326
|
const textContent = textNode.getTextContent();
|
|
370
327
|
const match = findOutermostMatch(textContent, textFormatTransformersIndex);
|
|
371
|
-
|
|
372
328
|
if (!match) {
|
|
373
329
|
// Once text format processing is done run text match transformers, as it
|
|
374
330
|
// only can span within single text node (unline formats that can cover multiple nodes)
|
|
375
331
|
importTextMatchTransformers(textNode, textMatchTransformers);
|
|
376
332
|
return;
|
|
377
333
|
}
|
|
334
|
+
let currentNode, remainderNode, leadingNode;
|
|
378
335
|
|
|
379
|
-
|
|
336
|
+
// If matching full content there's no need to run splitText and can reuse existing textNode
|
|
380
337
|
// to update its content and apply format. E.g. for **_Hello_** string after applying bold
|
|
381
338
|
// format (**) it will reuse the same text node to apply italic (_)
|
|
382
|
-
|
|
383
339
|
if (match[0] === textContent) {
|
|
384
340
|
currentNode = textNode;
|
|
385
341
|
} else {
|
|
386
342
|
const startIndex = match.index || 0;
|
|
387
343
|
const endIndex = startIndex + match[0].length;
|
|
388
|
-
|
|
389
344
|
if (startIndex === 0) {
|
|
390
345
|
[currentNode, remainderNode] = textNode.splitText(endIndex);
|
|
391
346
|
} else {
|
|
392
347
|
[leadingNode, currentNode, remainderNode] = textNode.splitText(startIndex, endIndex);
|
|
393
348
|
}
|
|
394
349
|
}
|
|
395
|
-
|
|
396
350
|
currentNode.setTextContent(match[2]);
|
|
397
351
|
const transformer = textFormatTransformersIndex.transformersByTag[match[1]];
|
|
398
|
-
|
|
399
352
|
if (transformer) {
|
|
400
353
|
for (const format of transformer.format) {
|
|
401
354
|
if (!currentNode.hasFormat(format)) {
|
|
402
355
|
currentNode.toggleFormat(format);
|
|
403
356
|
}
|
|
404
357
|
}
|
|
405
|
-
}
|
|
406
|
-
|
|
358
|
+
}
|
|
407
359
|
|
|
360
|
+
// Recursively run over inner text if it's not inline code
|
|
408
361
|
if (!currentNode.hasFormat('code')) {
|
|
409
362
|
importTextFormatTransformers(currentNode, textFormatTransformersIndex, textMatchTransformers);
|
|
410
|
-
}
|
|
411
|
-
|
|
363
|
+
}
|
|
412
364
|
|
|
365
|
+
// Run over leading/remaining text if any
|
|
413
366
|
if (leadingNode) {
|
|
414
367
|
importTextFormatTransformers(leadingNode, textFormatTransformersIndex, textMatchTransformers);
|
|
415
368
|
}
|
|
416
|
-
|
|
417
369
|
if (remainderNode) {
|
|
418
370
|
importTextFormatTransformers(remainderNode, textFormatTransformersIndex, textMatchTransformers);
|
|
419
371
|
}
|
|
420
372
|
}
|
|
421
|
-
|
|
422
373
|
function importTextMatchTransformers(textNode_, textMatchTransformers) {
|
|
423
374
|
let textNode = textNode_;
|
|
424
|
-
|
|
425
375
|
mainLoop: while (textNode) {
|
|
426
376
|
for (const transformer of textMatchTransformers) {
|
|
427
377
|
const match = textNode.getTextContent().match(transformer.importRegExp);
|
|
428
|
-
|
|
429
378
|
if (!match) {
|
|
430
379
|
continue;
|
|
431
380
|
}
|
|
432
|
-
|
|
433
381
|
const startIndex = match.index || 0;
|
|
434
382
|
const endIndex = startIndex + match[0].length;
|
|
435
383
|
let replaceNode, leftTextNode, rightTextNode;
|
|
436
|
-
|
|
437
384
|
if (startIndex === 0) {
|
|
438
385
|
[replaceNode, textNode] = textNode.splitText(endIndex);
|
|
439
386
|
} else {
|
|
440
387
|
[leftTextNode, replaceNode, rightTextNode] = textNode.splitText(startIndex, endIndex);
|
|
441
388
|
}
|
|
442
|
-
|
|
443
389
|
if (leftTextNode) {
|
|
444
390
|
importTextMatchTransformers(leftTextNode, textMatchTransformers);
|
|
445
391
|
}
|
|
446
|
-
|
|
447
392
|
if (rightTextNode) {
|
|
448
393
|
textNode = rightTextNode;
|
|
449
394
|
}
|
|
450
|
-
|
|
451
395
|
transformer.replace(replaceNode, match);
|
|
452
396
|
continue mainLoop;
|
|
453
397
|
}
|
|
454
|
-
|
|
455
398
|
break;
|
|
456
399
|
}
|
|
457
|
-
}
|
|
458
|
-
|
|
400
|
+
}
|
|
459
401
|
|
|
402
|
+
// Finds first "<tag>content<tag>" match that is not nested into another tag
|
|
460
403
|
function findOutermostMatch(textContent, textTransformersIndex) {
|
|
461
404
|
const openTagsMatch = textContent.match(textTransformersIndex.openTagsRegExp);
|
|
462
|
-
|
|
463
405
|
if (openTagsMatch == null) {
|
|
464
406
|
return null;
|
|
465
407
|
}
|
|
466
|
-
|
|
467
408
|
for (const match of openTagsMatch) {
|
|
468
409
|
// Open tags reg exp might capture leading space so removing it
|
|
469
410
|
// before using match to find transformer
|
|
470
411
|
const tag = match.replace(/^\s/, '');
|
|
471
412
|
const fullMatchRegExp = textTransformersIndex.fullMatchRegExpByTag[tag];
|
|
472
|
-
|
|
473
413
|
if (fullMatchRegExp == null) {
|
|
474
414
|
continue;
|
|
475
415
|
}
|
|
476
|
-
|
|
477
416
|
const fullMatch = textContent.match(fullMatchRegExp);
|
|
478
417
|
const transformer = textTransformersIndex.transformersByTag[tag];
|
|
479
|
-
|
|
480
418
|
if (fullMatch != null && transformer != null) {
|
|
481
419
|
if (transformer.intraword !== false) {
|
|
482
420
|
return fullMatch;
|
|
483
|
-
}
|
|
484
|
-
// or surrounded with space/punctuation/newline
|
|
485
|
-
|
|
421
|
+
}
|
|
486
422
|
|
|
423
|
+
// For non-intraword transformers checking if it's within a word
|
|
424
|
+
// or surrounded with space/punctuation/newline
|
|
487
425
|
const {
|
|
488
426
|
index = 0
|
|
489
427
|
} = fullMatch;
|
|
490
428
|
const beforeChar = textContent[index - 1];
|
|
491
429
|
const afterChar = textContent[index + fullMatch[0].length];
|
|
492
|
-
|
|
493
430
|
if ((!beforeChar || PUNCTUATION_OR_SPACE.test(beforeChar)) && (!afterChar || PUNCTUATION_OR_SPACE.test(afterChar))) {
|
|
494
431
|
return fullMatch;
|
|
495
432
|
}
|
|
496
433
|
}
|
|
497
434
|
}
|
|
498
|
-
|
|
499
435
|
return null;
|
|
500
436
|
}
|
|
501
|
-
|
|
502
437
|
function createTextFormatTransformersIndex(textTransformers) {
|
|
503
438
|
const transformersByTag = {};
|
|
504
439
|
const fullMatchRegExpByTag = {};
|
|
505
440
|
const openTagsRegExp = [];
|
|
506
441
|
const escapeRegExp = `(?<![\\\\])`;
|
|
507
|
-
|
|
508
442
|
for (const transformer of textTransformers) {
|
|
509
443
|
const {
|
|
510
444
|
tag
|
|
@@ -512,14 +446,12 @@ function createTextFormatTransformersIndex(textTransformers) {
|
|
|
512
446
|
transformersByTag[tag] = transformer;
|
|
513
447
|
const tagRegExp = tag.replace(/(\*|\^|\+)/g, '\\$1');
|
|
514
448
|
openTagsRegExp.push(tagRegExp);
|
|
515
|
-
|
|
516
449
|
if (IS_SAFARI || IS_IOS || IS_APPLE_WEBKIT) {
|
|
517
450
|
fullMatchRegExpByTag[tag] = new RegExp(`(${tagRegExp})(?![${tagRegExp}\\s])(.*?[^${tagRegExp}\\s])${tagRegExp}(?!${tagRegExp})`);
|
|
518
451
|
} else {
|
|
519
452
|
fullMatchRegExpByTag[tag] = new RegExp(`(?<![\\\\${tagRegExp}])(${tagRegExp})((\\\\${tagRegExp})?.*?[^${tagRegExp}\\s](\\\\${tagRegExp})?)((?<!\\\\)|(?<=\\\\\\\\))(${tagRegExp})(?![\\\\${tagRegExp}])`);
|
|
520
453
|
}
|
|
521
454
|
}
|
|
522
|
-
|
|
523
455
|
return {
|
|
524
456
|
// Reg exp to find open tag + content + close tag
|
|
525
457
|
fullMatchRegExpByTag,
|
|
@@ -536,31 +468,27 @@ function createTextFormatTransformersIndex(textTransformers) {
|
|
|
536
468
|
* LICENSE file in the root directory of this source tree.
|
|
537
469
|
*
|
|
538
470
|
*/
|
|
539
|
-
|
|
540
471
|
function runElementTransformers(parentNode, anchorNode, anchorOffset, elementTransformers) {
|
|
541
472
|
const grandParentNode = parentNode.getParent();
|
|
542
|
-
|
|
543
473
|
if (!lexical.$isRootOrShadowRoot(grandParentNode) || parentNode.getFirstChild() !== anchorNode) {
|
|
544
474
|
return false;
|
|
545
475
|
}
|
|
476
|
+
const textContent = anchorNode.getTextContent();
|
|
546
477
|
|
|
547
|
-
|
|
478
|
+
// Checking for anchorOffset position to prevent any checks for cases when caret is too far
|
|
548
479
|
// from a line start to be a part of block-level markdown trigger.
|
|
549
480
|
//
|
|
550
481
|
// TODO:
|
|
551
482
|
// Can have a quick check if caret is close enough to the beginning of the string (e.g. offset less than 10-20)
|
|
552
483
|
// since otherwise it won't be a markdown shortcut, but tables are exception
|
|
553
|
-
|
|
554
484
|
if (textContent[anchorOffset - 1] !== ' ') {
|
|
555
485
|
return false;
|
|
556
486
|
}
|
|
557
|
-
|
|
558
487
|
for (const {
|
|
559
488
|
regExp,
|
|
560
489
|
replace
|
|
561
490
|
} of elementTransformers) {
|
|
562
491
|
const match = textContent.match(regExp);
|
|
563
|
-
|
|
564
492
|
if (match && match[0].length === anchorOffset) {
|
|
565
493
|
const nextSiblings = anchorNode.getNextSiblings();
|
|
566
494
|
const [leadingNode, remainderNode] = anchorNode.splitText(anchorOffset);
|
|
@@ -570,131 +498,115 @@ function runElementTransformers(parentNode, anchorNode, anchorOffset, elementTra
|
|
|
570
498
|
return true;
|
|
571
499
|
}
|
|
572
500
|
}
|
|
573
|
-
|
|
574
501
|
return false;
|
|
575
502
|
}
|
|
576
|
-
|
|
577
503
|
function runTextMatchTransformers(anchorNode, anchorOffset, transformersByTrigger) {
|
|
578
504
|
let textContent = anchorNode.getTextContent();
|
|
579
505
|
const lastChar = textContent[anchorOffset - 1];
|
|
580
506
|
const transformers = transformersByTrigger[lastChar];
|
|
581
|
-
|
|
582
507
|
if (transformers == null) {
|
|
583
508
|
return false;
|
|
584
|
-
}
|
|
585
|
-
// reg exp match up to a string end (caret position)
|
|
586
|
-
|
|
509
|
+
}
|
|
587
510
|
|
|
511
|
+
// If typing in the middle of content, remove the tail to do
|
|
512
|
+
// reg exp match up to a string end (caret position)
|
|
588
513
|
if (anchorOffset < textContent.length) {
|
|
589
514
|
textContent = textContent.slice(0, anchorOffset);
|
|
590
515
|
}
|
|
591
|
-
|
|
592
516
|
for (const transformer of transformers) {
|
|
593
517
|
const match = textContent.match(transformer.regExp);
|
|
594
|
-
|
|
595
518
|
if (match === null) {
|
|
596
519
|
continue;
|
|
597
520
|
}
|
|
598
|
-
|
|
599
521
|
const startIndex = match.index || 0;
|
|
600
522
|
const endIndex = startIndex + match[0].length;
|
|
601
523
|
let replaceNode;
|
|
602
|
-
|
|
603
524
|
if (startIndex === 0) {
|
|
604
525
|
[replaceNode] = anchorNode.splitText(endIndex);
|
|
605
526
|
} else {
|
|
606
527
|
[, replaceNode] = anchorNode.splitText(startIndex, endIndex);
|
|
607
528
|
}
|
|
608
|
-
|
|
609
529
|
replaceNode.selectNext(0, 0);
|
|
610
530
|
transformer.replace(replaceNode, match);
|
|
611
531
|
return true;
|
|
612
532
|
}
|
|
613
|
-
|
|
614
533
|
return false;
|
|
615
534
|
}
|
|
616
|
-
|
|
617
535
|
function runTextFormatTransformers(anchorNode, anchorOffset, textFormatTransformers) {
|
|
618
536
|
const textContent = anchorNode.getTextContent();
|
|
619
537
|
const closeTagEndIndex = anchorOffset - 1;
|
|
620
|
-
const closeChar = textContent[closeTagEndIndex];
|
|
621
|
-
|
|
538
|
+
const closeChar = textContent[closeTagEndIndex];
|
|
539
|
+
// Quick check if we're possibly at the end of inline markdown style
|
|
622
540
|
const matchers = textFormatTransformers[closeChar];
|
|
623
|
-
|
|
624
541
|
if (!matchers) {
|
|
625
542
|
return false;
|
|
626
543
|
}
|
|
627
|
-
|
|
628
544
|
for (const matcher of matchers) {
|
|
629
545
|
const {
|
|
630
546
|
tag
|
|
631
547
|
} = matcher;
|
|
632
548
|
const tagLength = tag.length;
|
|
633
|
-
const closeTagStartIndex = closeTagEndIndex - tagLength + 1;
|
|
549
|
+
const closeTagStartIndex = closeTagEndIndex - tagLength + 1;
|
|
634
550
|
|
|
551
|
+
// If tag is not single char check if rest of it matches with text content
|
|
635
552
|
if (tagLength > 1) {
|
|
636
553
|
if (!isEqualSubString(textContent, closeTagStartIndex, tag, 0, tagLength)) {
|
|
637
554
|
continue;
|
|
638
555
|
}
|
|
639
|
-
}
|
|
640
|
-
|
|
556
|
+
}
|
|
641
557
|
|
|
558
|
+
// Space before closing tag cancels inline markdown
|
|
642
559
|
if (textContent[closeTagStartIndex - 1] === ' ') {
|
|
643
560
|
continue;
|
|
644
|
-
}
|
|
645
|
-
|
|
561
|
+
}
|
|
646
562
|
|
|
563
|
+
// Some tags can not be used within words, hence should have newline/space/punctuation after it
|
|
647
564
|
const afterCloseTagChar = textContent[closeTagEndIndex + 1];
|
|
648
|
-
|
|
649
565
|
if (matcher.intraword === false && afterCloseTagChar && !PUNCTUATION_OR_SPACE.test(afterCloseTagChar)) {
|
|
650
566
|
continue;
|
|
651
567
|
}
|
|
652
|
-
|
|
653
568
|
const closeNode = anchorNode;
|
|
654
569
|
let openNode = closeNode;
|
|
655
|
-
let openTagStartIndex = getOpenTagStartIndex(textContent, closeTagStartIndex, tag);
|
|
656
|
-
// if haven't found it within the same text node as closing tag
|
|
570
|
+
let openTagStartIndex = getOpenTagStartIndex(textContent, closeTagStartIndex, tag);
|
|
657
571
|
|
|
572
|
+
// Go through text node siblings and search for opening tag
|
|
573
|
+
// if haven't found it within the same text node as closing tag
|
|
658
574
|
let sibling = openNode;
|
|
659
|
-
|
|
660
575
|
while (openTagStartIndex < 0 && (sibling = sibling.getPreviousSibling())) {
|
|
661
576
|
if (lexical.$isLineBreakNode(sibling)) {
|
|
662
577
|
break;
|
|
663
578
|
}
|
|
664
|
-
|
|
665
579
|
if (lexical.$isTextNode(sibling)) {
|
|
666
580
|
const siblingTextContent = sibling.getTextContent();
|
|
667
581
|
openNode = sibling;
|
|
668
582
|
openTagStartIndex = getOpenTagStartIndex(siblingTextContent, siblingTextContent.length, tag);
|
|
669
583
|
}
|
|
670
|
-
}
|
|
671
|
-
|
|
584
|
+
}
|
|
672
585
|
|
|
586
|
+
// Opening tag is not found
|
|
673
587
|
if (openTagStartIndex < 0) {
|
|
674
588
|
continue;
|
|
675
|
-
}
|
|
676
|
-
|
|
589
|
+
}
|
|
677
590
|
|
|
591
|
+
// No content between opening and closing tag
|
|
678
592
|
if (openNode === closeNode && openTagStartIndex + tagLength === closeTagStartIndex) {
|
|
679
593
|
continue;
|
|
680
|
-
}
|
|
681
|
-
|
|
594
|
+
}
|
|
682
595
|
|
|
596
|
+
// Checking longer tags for repeating chars (e.g. *** vs **)
|
|
683
597
|
const prevOpenNodeText = openNode.getTextContent();
|
|
684
|
-
|
|
685
598
|
if (openTagStartIndex > 0 && prevOpenNodeText[openTagStartIndex - 1] === closeChar) {
|
|
686
599
|
continue;
|
|
687
|
-
}
|
|
688
|
-
|
|
600
|
+
}
|
|
689
601
|
|
|
602
|
+
// Some tags can not be used within words, hence should have newline/space/punctuation before it
|
|
690
603
|
const beforeOpenTagChar = prevOpenNodeText[openTagStartIndex - 1];
|
|
691
|
-
|
|
692
604
|
if (matcher.intraword === false && beforeOpenTagChar && !PUNCTUATION_OR_SPACE.test(beforeOpenTagChar)) {
|
|
693
605
|
continue;
|
|
694
|
-
}
|
|
695
|
-
// to prevent any offset shifts if we start from opening one)
|
|
696
|
-
|
|
606
|
+
}
|
|
697
607
|
|
|
608
|
+
// Clean text from opening and closing tags (starting from closing tag
|
|
609
|
+
// to prevent any offset shifts if we start from opening one)
|
|
698
610
|
const prevCloseNodeText = closeNode.getTextContent();
|
|
699
611
|
const closeNodeText = prevCloseNodeText.slice(0, closeTagStartIndex) + prevCloseNodeText.slice(closeTagEndIndex + 1);
|
|
700
612
|
closeNode.setTextContent(closeNodeText);
|
|
@@ -702,62 +614,55 @@ function runTextFormatTransformers(anchorNode, anchorOffset, textFormatTransform
|
|
|
702
614
|
openNode.setTextContent(openNodeText.slice(0, openTagStartIndex) + openNodeText.slice(openTagStartIndex + tagLength));
|
|
703
615
|
const selection = lexical.$getSelection();
|
|
704
616
|
const nextSelection = lexical.$createRangeSelection();
|
|
705
|
-
lexical.$setSelection(nextSelection);
|
|
706
|
-
|
|
617
|
+
lexical.$setSelection(nextSelection);
|
|
618
|
+
// Adjust offset based on deleted chars
|
|
707
619
|
const newOffset = closeTagEndIndex - tagLength * (openNode === closeNode ? 2 : 1) + 1;
|
|
708
620
|
nextSelection.anchor.set(openNode.__key, openTagStartIndex, 'text');
|
|
709
|
-
nextSelection.focus.set(closeNode.__key, newOffset, 'text');
|
|
621
|
+
nextSelection.focus.set(closeNode.__key, newOffset, 'text');
|
|
710
622
|
|
|
623
|
+
// Apply formatting to selected text
|
|
711
624
|
for (const format of matcher.format) {
|
|
712
625
|
if (!nextSelection.hasFormat(format)) {
|
|
713
626
|
nextSelection.formatText(format);
|
|
714
627
|
}
|
|
715
|
-
}
|
|
716
|
-
|
|
628
|
+
}
|
|
717
629
|
|
|
718
|
-
|
|
630
|
+
// Collapse selection up to the focus point
|
|
631
|
+
nextSelection.anchor.set(nextSelection.focus.key, nextSelection.focus.offset, nextSelection.focus.type);
|
|
719
632
|
|
|
633
|
+
// Remove formatting from collapsed selection
|
|
720
634
|
for (const format of matcher.format) {
|
|
721
635
|
if (nextSelection.hasFormat(format)) {
|
|
722
636
|
nextSelection.toggleFormat(format);
|
|
723
637
|
}
|
|
724
638
|
}
|
|
725
|
-
|
|
726
639
|
if (lexical.$isRangeSelection(selection)) {
|
|
727
640
|
nextSelection.format = selection.format;
|
|
728
641
|
}
|
|
729
|
-
|
|
730
642
|
return true;
|
|
731
643
|
}
|
|
732
|
-
|
|
733
644
|
return false;
|
|
734
645
|
}
|
|
735
|
-
|
|
736
646
|
function getOpenTagStartIndex(string, maxIndex, tag) {
|
|
737
647
|
const tagLength = tag.length;
|
|
738
|
-
|
|
739
648
|
for (let i = maxIndex; i >= tagLength; i--) {
|
|
740
649
|
const startIndex = i - tagLength;
|
|
741
|
-
|
|
742
|
-
|
|
650
|
+
if (isEqualSubString(string, startIndex, tag, 0, tagLength) &&
|
|
651
|
+
// Space after opening tag cancels transformation
|
|
743
652
|
string[startIndex + tagLength] !== ' ') {
|
|
744
653
|
return startIndex;
|
|
745
654
|
}
|
|
746
655
|
}
|
|
747
|
-
|
|
748
656
|
return -1;
|
|
749
657
|
}
|
|
750
|
-
|
|
751
658
|
function isEqualSubString(stringA, aStart, stringB, bStart, length) {
|
|
752
659
|
for (let i = 0; i < length; i++) {
|
|
753
660
|
if (stringA[aStart + i] !== stringB[bStart + i]) {
|
|
754
661
|
return false;
|
|
755
662
|
}
|
|
756
663
|
}
|
|
757
|
-
|
|
758
664
|
return true;
|
|
759
665
|
}
|
|
760
|
-
|
|
761
666
|
function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
|
|
762
667
|
const byType = transformersByType(transformers);
|
|
763
668
|
const textFormatTransformersIndex = indexBy(byType.textFormat, ({
|
|
@@ -766,13 +671,10 @@ function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
|
|
|
766
671
|
const textMatchTransformersIndex = indexBy(byType.textMatch, ({
|
|
767
672
|
trigger
|
|
768
673
|
}) => trigger);
|
|
769
|
-
|
|
770
674
|
for (const transformer of transformers) {
|
|
771
675
|
const type = transformer.type;
|
|
772
|
-
|
|
773
676
|
if (type === 'element' || type === 'text-match') {
|
|
774
677
|
const dependencies = transformer.dependencies;
|
|
775
|
-
|
|
776
678
|
for (const node of dependencies) {
|
|
777
679
|
if (!editor.hasNode(node)) {
|
|
778
680
|
{
|
|
@@ -782,19 +684,15 @@ function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
|
|
|
782
684
|
}
|
|
783
685
|
}
|
|
784
686
|
}
|
|
785
|
-
|
|
786
687
|
const transform = (parentNode, anchorNode, anchorOffset) => {
|
|
787
688
|
if (runElementTransformers(parentNode, anchorNode, anchorOffset, byType.element)) {
|
|
788
689
|
return;
|
|
789
690
|
}
|
|
790
|
-
|
|
791
691
|
if (runTextMatchTransformers(anchorNode, anchorOffset, textMatchTransformersIndex)) {
|
|
792
692
|
return;
|
|
793
693
|
}
|
|
794
|
-
|
|
795
694
|
runTextFormatTransformers(anchorNode, anchorOffset, textFormatTransformersIndex);
|
|
796
695
|
};
|
|
797
|
-
|
|
798
696
|
return editor.registerUpdateListener(({
|
|
799
697
|
tags,
|
|
800
698
|
dirtyLeaves,
|
|
@@ -804,41 +702,32 @@ function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
|
|
|
804
702
|
// Ignore updates from undo/redo (as changes already calculated)
|
|
805
703
|
if (tags.has('historic')) {
|
|
806
704
|
return;
|
|
807
|
-
}
|
|
808
|
-
|
|
705
|
+
}
|
|
809
706
|
|
|
707
|
+
// If editor is still composing (i.e. backticks) we must wait before the user confirms the key
|
|
810
708
|
if (editor.isComposing()) {
|
|
811
709
|
return;
|
|
812
710
|
}
|
|
813
|
-
|
|
814
711
|
const selection = editorState.read(lexical.$getSelection);
|
|
815
712
|
const prevSelection = prevEditorState.read(lexical.$getSelection);
|
|
816
|
-
|
|
817
713
|
if (!lexical.$isRangeSelection(prevSelection) || !lexical.$isRangeSelection(selection) || !selection.isCollapsed()) {
|
|
818
714
|
return;
|
|
819
715
|
}
|
|
820
|
-
|
|
821
716
|
const anchorKey = selection.anchor.key;
|
|
822
717
|
const anchorOffset = selection.anchor.offset;
|
|
823
|
-
|
|
824
718
|
const anchorNode = editorState._nodeMap.get(anchorKey);
|
|
825
|
-
|
|
826
719
|
if (!lexical.$isTextNode(anchorNode) || !dirtyLeaves.has(anchorKey) || anchorOffset !== 1 && anchorOffset > prevSelection.anchor.offset + 1) {
|
|
827
720
|
return;
|
|
828
721
|
}
|
|
829
|
-
|
|
830
722
|
editor.update(() => {
|
|
831
723
|
// Markdown is not available inside code
|
|
832
724
|
if (anchorNode.hasFormat('code')) {
|
|
833
725
|
return;
|
|
834
726
|
}
|
|
835
|
-
|
|
836
727
|
const parentNode = anchorNode.getParent();
|
|
837
|
-
|
|
838
728
|
if (parentNode === null || code.$isCodeNode(parentNode)) {
|
|
839
729
|
return;
|
|
840
730
|
}
|
|
841
|
-
|
|
842
731
|
transform(parentNode, anchorNode, selection.anchor.offset);
|
|
843
732
|
});
|
|
844
733
|
});
|
|
@@ -851,7 +740,6 @@ function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
|
|
|
851
740
|
* LICENSE file in the root directory of this source tree.
|
|
852
741
|
*
|
|
853
742
|
*/
|
|
854
|
-
|
|
855
743
|
const createBlockNode = createNode => {
|
|
856
744
|
return (parentNode, children, match) => {
|
|
857
745
|
const node = createNode(match);
|
|
@@ -859,28 +747,24 @@ const createBlockNode = createNode => {
|
|
|
859
747
|
parentNode.replace(node);
|
|
860
748
|
node.select(0, 0);
|
|
861
749
|
};
|
|
862
|
-
};
|
|
863
|
-
// TODO: should be an option
|
|
864
|
-
|
|
750
|
+
};
|
|
865
751
|
|
|
752
|
+
// Amount of spaces that define indentation level
|
|
753
|
+
// TODO: should be an option
|
|
866
754
|
const LIST_INDENT_SIZE = 4;
|
|
867
|
-
|
|
868
755
|
const listReplace = listType => {
|
|
869
756
|
return (parentNode, children, match) => {
|
|
870
757
|
const previousNode = parentNode.getPreviousSibling();
|
|
871
758
|
const nextNode = parentNode.getNextSibling();
|
|
872
759
|
const listItem = list.$createListItemNode(listType === 'check' ? match[3] === 'x' : undefined);
|
|
873
|
-
|
|
874
760
|
if (list.$isListNode(nextNode) && nextNode.getListType() === listType) {
|
|
875
761
|
const firstChild = nextNode.getFirstChild();
|
|
876
|
-
|
|
877
762
|
if (firstChild !== null) {
|
|
878
763
|
firstChild.insertBefore(listItem);
|
|
879
764
|
} else {
|
|
880
765
|
// should never happen, but let's handle gracefully, just in case.
|
|
881
766
|
nextNode.append(listItem);
|
|
882
767
|
}
|
|
883
|
-
|
|
884
768
|
parentNode.remove();
|
|
885
769
|
} else if (list.$isListNode(previousNode) && previousNode.getListType() === listType) {
|
|
886
770
|
previousNode.append(listItem);
|
|
@@ -890,33 +774,27 @@ const listReplace = listType => {
|
|
|
890
774
|
list$1.append(listItem);
|
|
891
775
|
parentNode.replace(list$1);
|
|
892
776
|
}
|
|
893
|
-
|
|
894
777
|
listItem.append(...children);
|
|
895
778
|
listItem.select(0, 0);
|
|
896
779
|
const indent = Math.floor(match[1].length / LIST_INDENT_SIZE);
|
|
897
|
-
|
|
898
780
|
if (indent) {
|
|
899
781
|
listItem.setIndent(indent);
|
|
900
782
|
}
|
|
901
783
|
};
|
|
902
784
|
};
|
|
903
|
-
|
|
904
785
|
const listExport = (listNode, exportChildren, depth) => {
|
|
905
786
|
const output = [];
|
|
906
787
|
const children = listNode.getChildren();
|
|
907
788
|
let index = 0;
|
|
908
|
-
|
|
909
789
|
for (const listItemNode of children) {
|
|
910
790
|
if (list.$isListItemNode(listItemNode)) {
|
|
911
791
|
if (listItemNode.getChildrenSize() === 1) {
|
|
912
792
|
const firstChild = listItemNode.getFirstChild();
|
|
913
|
-
|
|
914
793
|
if (list.$isListNode(firstChild)) {
|
|
915
794
|
output.push(listExport(firstChild, exportChildren, depth + 1));
|
|
916
795
|
continue;
|
|
917
796
|
}
|
|
918
797
|
}
|
|
919
|
-
|
|
920
798
|
const indent = ' '.repeat(depth * LIST_INDENT_SIZE);
|
|
921
799
|
const listType = listNode.getListType();
|
|
922
800
|
const prefix = listType === 'number' ? `${listNode.getStart() + index}. ` : listType === 'check' ? `- [${listItemNode.getChecked() ? 'x' : ' '}] ` : '- ';
|
|
@@ -924,17 +802,14 @@ const listExport = (listNode, exportChildren, depth) => {
|
|
|
924
802
|
index++;
|
|
925
803
|
}
|
|
926
804
|
}
|
|
927
|
-
|
|
928
805
|
return output.join('\n');
|
|
929
806
|
};
|
|
930
|
-
|
|
931
807
|
const HEADING = {
|
|
932
808
|
dependencies: [richText.HeadingNode],
|
|
933
809
|
export: (node, exportChildren) => {
|
|
934
810
|
if (!richText.$isHeadingNode(node)) {
|
|
935
811
|
return null;
|
|
936
812
|
}
|
|
937
|
-
|
|
938
813
|
const level = Number(node.getTag().slice(1));
|
|
939
814
|
return '#'.repeat(level) + ' ' + exportChildren(node);
|
|
940
815
|
},
|
|
@@ -951,21 +826,17 @@ const QUOTE = {
|
|
|
951
826
|
if (!richText.$isQuoteNode(node)) {
|
|
952
827
|
return null;
|
|
953
828
|
}
|
|
954
|
-
|
|
955
829
|
const lines = exportChildren(node).split('\n');
|
|
956
830
|
const output = [];
|
|
957
|
-
|
|
958
831
|
for (const line of lines) {
|
|
959
832
|
output.push('> ' + line);
|
|
960
833
|
}
|
|
961
|
-
|
|
962
834
|
return output.join('\n');
|
|
963
835
|
},
|
|
964
836
|
regExp: /^>\s/,
|
|
965
837
|
replace: (parentNode, children, _match, isImport) => {
|
|
966
838
|
if (isImport) {
|
|
967
839
|
const previousNode = parentNode.getPreviousSibling();
|
|
968
|
-
|
|
969
840
|
if (richText.$isQuoteNode(previousNode)) {
|
|
970
841
|
previousNode.splice(previousNode.getChildrenSize(), 0, [lexical.$createLineBreakNode(), ...children]);
|
|
971
842
|
previousNode.select(0, 0);
|
|
@@ -973,7 +844,6 @@ const QUOTE = {
|
|
|
973
844
|
return;
|
|
974
845
|
}
|
|
975
846
|
}
|
|
976
|
-
|
|
977
847
|
const node = richText.$createQuoteNode();
|
|
978
848
|
node.append(...children);
|
|
979
849
|
parentNode.replace(node);
|
|
@@ -987,7 +857,6 @@ const CODE = {
|
|
|
987
857
|
if (!code.$isCodeNode(node)) {
|
|
988
858
|
return null;
|
|
989
859
|
}
|
|
990
|
-
|
|
991
860
|
const textContent = node.getTextContent();
|
|
992
861
|
return '```' + (node.getLanguage() || '') + (textContent ? '\n' + textContent : '') + '\n' + '```';
|
|
993
862
|
},
|
|
@@ -1071,23 +940,23 @@ const ITALIC_UNDERSCORE = {
|
|
|
1071
940
|
intraword: false,
|
|
1072
941
|
tag: '_',
|
|
1073
942
|
type: 'text-format'
|
|
1074
|
-
};
|
|
943
|
+
};
|
|
944
|
+
|
|
945
|
+
// Order of text transformers matters:
|
|
1075
946
|
//
|
|
1076
947
|
// - code should go first as it prevents any transformations inside
|
|
1077
948
|
// - then longer tags match (e.g. ** or __ should go before * or _)
|
|
1078
|
-
|
|
1079
949
|
const LINK = {
|
|
1080
950
|
dependencies: [link.LinkNode],
|
|
1081
951
|
export: (node, exportChildren, exportFormat) => {
|
|
1082
952
|
if (!link.$isLinkNode(node)) {
|
|
1083
953
|
return null;
|
|
1084
954
|
}
|
|
1085
|
-
|
|
1086
955
|
const title = node.getTitle();
|
|
1087
956
|
const linkContent = title ? `[${node.getTextContent()}](${node.getURL()} "${title}")` : `[${node.getTextContent()}](${node.getURL()})`;
|
|
1088
|
-
const firstChild = node.getFirstChild();
|
|
957
|
+
const firstChild = node.getFirstChild();
|
|
958
|
+
// Add text styles only if link has single text node inside. If it's more
|
|
1089
959
|
// then one we ignore it as markdown does not support nested styles for links
|
|
1090
|
-
|
|
1091
960
|
if (node.getChildrenSize() === 1 && lexical.$isTextNode(firstChild)) {
|
|
1092
961
|
return exportFormat(firstChild, linkContent);
|
|
1093
962
|
} else {
|
|
@@ -1111,20 +980,19 @@ const LINK = {
|
|
|
1111
980
|
};
|
|
1112
981
|
|
|
1113
982
|
/** @module @lexical/markdown */
|
|
1114
|
-
const ELEMENT_TRANSFORMERS = [HEADING, QUOTE, CODE, UNORDERED_LIST, ORDERED_LIST];
|
|
983
|
+
const ELEMENT_TRANSFORMERS = [HEADING, QUOTE, CODE, UNORDERED_LIST, ORDERED_LIST];
|
|
984
|
+
|
|
985
|
+
// Order of text format transformers matters:
|
|
1115
986
|
//
|
|
1116
987
|
// - code should go first as it prevents any transformations inside
|
|
1117
988
|
// - then longer tags match (e.g. ** or __ should go before * or _)
|
|
1118
|
-
|
|
1119
989
|
const TEXT_FORMAT_TRANSFORMERS = [INLINE_CODE, BOLD_ITALIC_STAR, BOLD_ITALIC_UNDERSCORE, BOLD_STAR, BOLD_UNDERSCORE, HIGHLIGHT, ITALIC_STAR, ITALIC_UNDERSCORE, STRIKETHROUGH];
|
|
1120
990
|
const TEXT_MATCH_TRANSFORMERS = [LINK];
|
|
1121
991
|
const TRANSFORMERS = [...ELEMENT_TRANSFORMERS, ...TEXT_FORMAT_TRANSFORMERS, ...TEXT_MATCH_TRANSFORMERS];
|
|
1122
|
-
|
|
1123
992
|
function $convertFromMarkdownString(markdown, transformers = TRANSFORMERS, node) {
|
|
1124
993
|
const importMarkdown = createMarkdownImport(transformers);
|
|
1125
994
|
return importMarkdown(markdown, node);
|
|
1126
995
|
}
|
|
1127
|
-
|
|
1128
996
|
function $convertToMarkdownString(transformers = TRANSFORMERS, node) {
|
|
1129
997
|
const exportMarkdown = createMarkdownExport(transformers);
|
|
1130
998
|
return exportMarkdown(node);
|
package/LexicalMarkdown.prod.js
CHANGED
|
@@ -4,26 +4,26 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
'use strict';var k=require("lexical"),t=require("@lexical/code"),
|
|
7
|
+
'use strict';var k=require("lexical"),t=require("@lexical/code"),z=require("@lexical/list"),B=require("@lexical/rich-text"),aa=require("@lexical/utils"),G=require("@lexical/link");function H(a,b){let c={};for(let d of a)a=b(d),c[a]?c[a].push(d):c[a]=[d];return c}function I(a){a=H(a,b=>b.type);return{element:a.element||[],textFormat:a["text-format"]||[],textMatch:a["text-match"]||[]}}let J=/[!-/:-@[-`{-~\s]/;
|
|
8
8
|
function ba(a){let b=I(a),c=b.textFormat.filter(d=>1===d.format.length);return d=>{let e=[];d=(d||k.$getRoot()).getChildren();for(let f of d)d=ca(f,b.element,c,b.textMatch),null!=d&&e.push(d);return e.join("\n\n")}}function ca(a,b,c,d){for(let e of b)if(b=e.export(a,f=>K(f,c,d)),null!=b)return b;return k.$isElementNode(a)?K(a,c,d):k.$isDecoratorNode(a)?a.getTextContent():null}
|
|
9
9
|
function K(a,b,c){let d=[];a=a.getChildren();a:for(let e of a){for(let f of c)if(a=f.export(e,g=>K(g,b,c),(g,l)=>L(g,l,b)),null!=a){d.push(a);continue a}k.$isLineBreakNode(e)?d.push("\n"):k.$isTextNode(e)?d.push(L(e,e.getTextContent(),b)):k.$isElementNode(e)?d.push(K(e,b,c)):k.$isDecoratorNode(e)&&d.push(e.getTextContent())}return d.join("")}
|
|
10
10
|
function L(a,b,c){let d=b.trim(),e=d,f=new Set;for(let l of c){c=l.format[0];let p=l.tag;if(M(a,c)&&!f.has(c)){f.add(c);var g=N(a,!0);M(g,c)||(e=p+e);g=N(a,!1);M(g,c)||(e+=p)}}return b.replace(d,e)}
|
|
11
11
|
function N(a,b){let c=b?a.getPreviousSibling():a.getNextSibling();c||(a=a.getParentOrThrow(),a.isInline()&&(c=b?a.getPreviousSibling():a.getNextSibling()));for(;c;){if(k.$isElementNode(c)){if(!c.isInline())break;a=b?c.getLastDescendant():c.getFirstDescendant();if(k.$isTextNode(a))return a;c=b?c.getPreviousSibling():c.getNextSibling()}if(k.$isTextNode(c))return c;if(!k.$isElementNode(c))break}return null}function M(a,b){return k.$isTextNode(a)&&a.hasFormat(b)}
|
|
12
|
-
let O="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement,da=O&&"documentMode"in document?document.documentMode:null;O&&/Mac|iPod|iPhone|iPad/.test(navigator.platform);O&&/^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);O&&"InputEvent"in window&&!da?"getTargetRanges"in new window.InputEvent("input"):!1;
|
|
13
|
-
|
|
12
|
+
let O="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement,da=O&&"documentMode"in document?document.documentMode:null;O&&/Mac|iPod|iPhone|iPad/.test(navigator.platform);O&&/^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);O&&"InputEvent"in window&&!da?"getTargetRanges"in new window.InputEvent("input"):!1;let P=O&&/Version\/[\d.]+.*Safari/.test(navigator.userAgent),Q=O&&/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream;
|
|
13
|
+
O&&/Android/.test(navigator.userAgent);let ea=O&&/^(?=.*Chrome).*/i.test(navigator.userAgent),R=O&&/AppleWebKit\/[\d.]+/.test(navigator.userAgent)&&!ea,fa=/^\s{0,3}$/,S=/^```(\w{1,10})?\s?$/;
|
|
14
14
|
function ha(a){let b=I(a),c=ia(b.textFormat);return(d,e)=>{d=d.split("\n");var f=d.length;e=e||k.$getRoot();e.clear();for(let h=0;h<f;h++){var g=d[h];a:{var l=d,p=h;var r=e;var y=l[p].match(S);if(y)for(var q=p,m=l.length;++q<m;)if(l[q].match(S)){y=t.$createCodeNode(y[1]);l=k.$createTextNode(l.slice(p+1,q).join("\n"));y.append(l);r.append(y);r=[y,q];break a}r=[null,p]}let [n,v]=r;if(null!=n)h=v;else{r=g;m=e;var w=b.element;q=c;l=b.textMatch;p=r.trim();y=k.$createTextNode(p);g=k.$createParagraphNode();
|
|
15
|
-
g.append(y);m.append(g);for(let {regExp:x,replace:u}of w)if(m=r.match(x)){y.setTextContent(r.slice(m[0].length));u(g,[y],m,!0);break}T(y,q,l);g.isAttached()&&0<p.length&&(r=g.getPreviousSibling(),k.$isParagraphNode(r)||B.$isQuoteNode(r)||
|
|
15
|
+
g.append(y);m.append(g);for(let {regExp:x,replace:u}of w)if(m=r.match(x)){y.setTextContent(r.slice(m[0].length));u(g,[y],m,!0);break}T(y,q,l);g.isAttached()&&0<p.length&&(r=g.getPreviousSibling(),k.$isParagraphNode(r)||B.$isQuoteNode(r)||z.$isListNode(r))&&(q=r,z.$isListNode(r)&&(r=r.getLastDescendant(),q=null==r?null:aa.$findMatchingParent(r,z.$isListItemNode)),null!=q&&0<q.getTextContentSize()&&(q.splice(q.getChildrenSize(),0,[k.$createLineBreakNode(),...g.getChildren()]),g.remove()))}}d=e.getChildren();
|
|
16
16
|
for(let h of d)d=h,k.$isParagraphNode(d)?(f=d.getFirstChild(),d=null==f||1===d.getChildrenSize()&&k.$isTextNode(f)&&fa.test(f.getTextContent())):d=!1,d&&h.remove();null!==k.$getSelection()&&e.selectEnd()}}
|
|
17
17
|
function T(a,b,c){var d=a.getTextContent();let e=ja(d,b);if(e){var f,g;if(e[0]===d)var l=a;else{d=e.index||0;let p=d+e[0].length;0===d?[l,f]=a.splitText(p):[g,l,f]=a.splitText(d,p)}l.setTextContent(e[2]);if(a=b.transformersByTag[e[1]])for(let p of a.format)l.hasFormat(p)||l.toggleFormat(p);l.hasFormat("code")||T(l,b,c);g&&T(g,b,c);f&&T(f,b,c)}else U(a,c)}
|
|
18
18
|
function U(a,b){a:for(;a;){for(let c of b){let d=a.getTextContent().match(c.importRegExp);if(!d)continue;let e=d.index||0,f=e+d[0].length,g,l,p;0===e?[g,a]=a.splitText(f):[l,g,p]=a.splitText(e,f);l&&U(l,b);p&&(a=p);c.replace(g,d);continue a}break}}
|
|
19
19
|
function ja(a,b){var c=a.match(b.openTagsRegExp);if(null==c)return null;for(let f of c){var d=f.replace(/^\s/,"");c=b.fullMatchRegExpByTag[d];if(null!=c&&(c=a.match(c),d=b.transformersByTag[d],null!=c&&null!=d)){if(!1!==d.intraword)return c;var {index:e=0}=c;d=a[e-1];e=a[e+c[0].length];if(!(d&&!J.test(d)||e&&!J.test(e)))return c}}return null}
|
|
20
20
|
function ia(a){let b={},c={},d=[];for(let e of a){({tag:a}=e);b[a]=e;let f=a.replace(/(\*|\^|\+)/g,"\\$1");d.push(f);c[a]=P||Q||R?new RegExp(`(${f})(?![${f}\\s])(.*?[^${f}\\s])${f}(?!${f})`):new RegExp(`(?<![\\\\${f}])(${f})((\\\\${f})?.*?[^${f}\\s](\\\\${f})?)((?<!\\\\)|(?<=\\\\\\\\))(${f})(?![\\\\${f}])`)}return{fullMatchRegExpByTag:c,openTagsRegExp:new RegExp((P||Q||R?"":"(?<![\\\\])")+"("+d.join("|")+")","g"),transformersByTag:b}}
|
|
21
21
|
function V(a,b,c){let d=c.length;for(;b>=d;b--){let e=b-d;if(W(a,e,c,0,d)&&" "!==a[e+d])return e}return-1}function W(a,b,c,d,e){for(let f=0;f<e;f++)if(a[b+f]!==c[d+f])return!1;return!0}
|
|
22
|
-
let ka=a=>(b,c,d)=>{d=a(d);d.append(...c);b.replace(d);d.select(0,0)},X=a=>(b,c,d)=>{var e=b.getPreviousSibling(),f=b.getNextSibling();const g=
|
|
23
|
-
4))&&g.setIndent(b)},Y=(a,b,c)=>{const d=[];var e=a.getChildren();let f=0;for(const l of e)if(
|
|
22
|
+
let ka=a=>(b,c,d)=>{d=a(d);d.append(...c);b.replace(d);d.select(0,0)},X=a=>(b,c,d)=>{var e=b.getPreviousSibling(),f=b.getNextSibling();const g=z.$createListItemNode("check"===a?"x"===d[3]:void 0);z.$isListNode(f)&&f.getListType()===a?(e=f.getFirstChild(),null!==e?e.insertBefore(g):f.append(g),b.remove()):z.$isListNode(e)&&e.getListType()===a?(e.append(g),b.remove()):(f=z.$createListNode(a,"number"===a?Number(d[2]):void 0),f.append(g),b.replace(f));g.append(...c);g.select(0,0);(b=Math.floor(d[1].length/
|
|
23
|
+
4))&&g.setIndent(b)},Y=(a,b,c)=>{const d=[];var e=a.getChildren();let f=0;for(const l of e)if(z.$isListItemNode(l)){if(1===l.getChildrenSize()&&(e=l.getFirstChild(),z.$isListNode(e))){d.push(Y(e,b,c+1));continue}e=" ".repeat(4*c);var g=a.getListType();g="number"===g?`${a.getStart()+f}. `:"check"===g?`- [${l.getChecked()?"x":" "}] `:"- ";d.push(e+g+b(l));f++}return d.join("\n")},la={dependencies:[B.HeadingNode],export:(a,b)=>{if(!B.$isHeadingNode(a))return null;const c=Number(a.getTag().slice(1));
|
|
24
24
|
return"#".repeat(c)+" "+b(a)},regExp:/^(#{1,6})\s/,replace:ka(a=>B.$createHeadingNode("h"+a[1].length)),type:"element"},ma={dependencies:[B.QuoteNode],export:(a,b)=>{if(!B.$isQuoteNode(a))return null;a=b(a).split("\n");b=[];for(const c of a)b.push("> "+c);return b.join("\n")},regExp:/^>\s/,replace:(a,b,c,d)=>{if(d&&(c=a.getPreviousSibling(),B.$isQuoteNode(c))){c.splice(c.getChildrenSize(),0,[k.$createLineBreakNode(),...b]);c.select(0,0);a.remove();return}c=B.$createQuoteNode();c.append(...b);a.replace(c);
|
|
25
|
-
c.select(0,0)},type:"element"},na={dependencies:[t.CodeNode],export:a=>{if(!t.$isCodeNode(a))return null;const b=a.getTextContent();return"```"+(a.getLanguage()||"")+(b?"\n"+b:"")+"\n```"},regExp:/^```(\w{1,10})?\s/,replace:ka(a=>t.$createCodeNode(a?a[1]:void 0)),type:"element"},oa={dependencies:[
|
|
26
|
-
Y(a,b,0):null,regExp:/^(\s*)(?:-\s)?\s?(\[(\s|x)?\])\s/i,replace:X("check"),type:"element"},qa={dependencies:[
|
|
25
|
+
c.select(0,0)},type:"element"},na={dependencies:[t.CodeNode],export:a=>{if(!t.$isCodeNode(a))return null;const b=a.getTextContent();return"```"+(a.getLanguage()||"")+(b?"\n"+b:"")+"\n```"},regExp:/^```(\w{1,10})?\s/,replace:ka(a=>t.$createCodeNode(a?a[1]:void 0)),type:"element"},oa={dependencies:[z.ListNode,z.ListItemNode],export:(a,b)=>z.$isListNode(a)?Y(a,b,0):null,regExp:/^(\s*)[-*+]\s/,replace:X("bullet"),type:"element"},pa={dependencies:[z.ListNode,z.ListItemNode],export:(a,b)=>z.$isListNode(a)?
|
|
26
|
+
Y(a,b,0):null,regExp:/^(\s*)(?:-\s)?\s?(\[(\s|x)?\])\s/i,replace:X("check"),type:"element"},qa={dependencies:[z.ListNode,z.ListItemNode],export:(a,b)=>z.$isListNode(a)?Y(a,b,0):null,regExp:/^(\s*)(\d{1,})\.\s/,replace:X("number"),type:"element"},ra={format:["code"],tag:"`",type:"text-format"},sa={format:["highlight"],tag:"==",type:"text-format"},ta={format:["bold","italic"],tag:"***",type:"text-format"},va={format:["bold","italic"],intraword:!1,tag:"___",type:"text-format"},wa={format:["bold"],tag:"**",
|
|
27
27
|
type:"text-format"},xa={format:["bold"],intraword:!1,tag:"__",type:"text-format"},ya={format:["strikethrough"],tag:"~~",type:"text-format"},za={format:["italic"],tag:"*",type:"text-format"},Aa={format:["italic"],intraword:!1,tag:"_",type:"text-format"},Ba={dependencies:[G.LinkNode],export:(a,b,c)=>{if(!G.$isLinkNode(a))return null;b=(b=a.getTitle())?`[${a.getTextContent()}](${a.getURL()} "${b}")`:`[${a.getTextContent()}](${a.getURL()})`;const d=a.getFirstChild();return 1===a.getChildrenSize()&&k.$isTextNode(d)?
|
|
28
28
|
c(d,b):b},importRegExp:/(?:\[([^[]+)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))/,regExp:/(?:\[([^[]+)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))$/,replace:(a,b)=>{const [,c,d,e]=b;b=G.$createLinkNode(d,{title:e});const f=k.$createTextNode(c);f.setFormat(a.getFormat());b.append(f);a.replace(b)},trigger:")",type:"text-match"},Ca=[la,ma,na,oa,qa],Da=[ra,ta,va,wa,xa,sa,za,Aa,ya],Ea=[Ba],Z=[...Ca,...Da,...Ea];
|
|
29
29
|
exports.$convertFromMarkdownString=function(a,b=Z,c){return ha(b)(a,c)};exports.$convertToMarkdownString=function(a=Z,b){return ba(a)(b)};exports.BOLD_ITALIC_STAR=ta;exports.BOLD_ITALIC_UNDERSCORE=va;exports.BOLD_STAR=wa;exports.BOLD_UNDERSCORE=xa;exports.CHECK_LIST=pa;exports.CODE=na;exports.ELEMENT_TRANSFORMERS=Ca;exports.HEADING=la;exports.HIGHLIGHT=sa;exports.INLINE_CODE=ra;exports.ITALIC_STAR=za;exports.ITALIC_UNDERSCORE=Aa;exports.LINK=Ba;exports.ORDERED_LIST=qa;exports.QUOTE=ma;
|
|
@@ -31,5 +31,5 @@ exports.STRIKETHROUGH=ya;exports.TEXT_FORMAT_TRANSFORMERS=Da;exports.TEXT_MATCH_
|
|
|
31
31
|
exports.registerMarkdownShortcuts=function(a,b=Z){let c=I(b),d=H(c.textFormat,({tag:f})=>f[f.length-1]),e=H(c.textMatch,({trigger:f})=>f);for(let f of b)if(b=f.type,"element"===b||"text-match"===b){b=f.dependencies;for(let g of b)if(!a.hasNode(g))throw Error(`MarkdownShortcuts: missing dependency ${g.getType()} for transformer. Ensure node dependency is included in editor initial config.`);}return a.registerUpdateListener(({tags:f,dirtyLeaves:g,editorState:l,prevEditorState:p})=>{if(!f.has("historic")&&
|
|
32
32
|
!a.isComposing()){var r=l.read(k.$getSelection);f=p.read(k.$getSelection);if(k.$isRangeSelection(f)&&k.$isRangeSelection(r)&&r.isCollapsed()){p=r.anchor.key;var y=r.anchor.offset,q=l._nodeMap.get(p);!k.$isTextNode(q)||!g.has(p)||1!==y&&y>f.anchor.offset+1||a.update(()=>{if(!q.hasFormat("code")){var m=q.getParent();if(null!==m&&!t.$isCodeNode(m)){var w=r.anchor.offset;b:{var h=c.element,n=m.getParent();if(k.$isRootOrShadowRoot(n)&&m.getFirstChild()===q&&(n=q.getTextContent()," "===n[w-1]))for(let {regExp:D,
|
|
33
33
|
replace:E}of h)if((h=n.match(D))&&h[0].length===w){n=q.getNextSiblings();let [F,ua]=q.splitText(w);F.remove();n=ua?[ua,...n]:n;E(m,n,h,!1);m=!0;break b}m=!1}if(!m){b:{h=q.getTextContent();m=e[h[w-1]];if(null!=m){w<h.length&&(h=h.slice(0,w));for(x of m)if(m=h.match(x.regExp),null!==m){h=m.index||0;n=h+m[0].length;var v=void 0;0===h?[v]=q.splitText(n):[,v]=q.splitText(h,n);v.selectNext(0,0);x.replace(v,m);var x=!0;break b}}x=!1}if(!x)b:{n=q.getTextContent();--w;var u=n[w];if(x=d[u])for(let D of x){var {tag:C}=
|
|
34
|
-
D;x=C.length;let E=w-x+1;if(!(1<x&&!W(n,E,C,0,x)||" "===n[E-1])&&(v=n[w+1],!1!==D.intraword||!v||J.test(v))){m=v=q;h=V(n,E,C);for(var
|
|
34
|
+
D;x=C.length;let E=w-x+1;if(!(1<x&&!W(n,E,C,0,x)||" "===n[E-1])&&(v=n[w+1],!1!==D.intraword||!v||J.test(v))){m=v=q;h=V(n,E,C);for(var A=m;0>h&&(A=A.getPreviousSibling())&&!k.$isLineBreakNode(A);)k.$isTextNode(A)&&(h=A.getTextContent(),m=A,h=V(h,h.length,C));if(!(0>h||m===v&&h+x===E||(C=m.getTextContent(),0<h&&C[h-1]===u||(A=C[h-1],!1===D.intraword&&A&&!J.test(A))))){n=v.getTextContent();n=n.slice(0,E)+n.slice(w+1);v.setTextContent(n);n=m===v?n:C;m.setTextContent(n.slice(0,h)+n.slice(h+x));n=k.$getSelection();
|
|
35
35
|
u=k.$createRangeSelection();k.$setSelection(u);w=w-x*(m===v?2:1)+1;u.anchor.set(m.__key,h,"text");u.focus.set(v.__key,w,"text");for(let F of D.format)u.hasFormat(F)||u.formatText(F);u.anchor.set(u.focus.key,u.focus.offset,u.focus.type);for(let F of D.format)u.hasFormat(F)&&u.toggleFormat(F);k.$isRangeSelection(n)&&(u.format=n.format);break b}}}}}}}})}}})}
|
package/package.json
CHANGED
|
@@ -8,18 +8,18 @@
|
|
|
8
8
|
"markdown"
|
|
9
9
|
],
|
|
10
10
|
"license": "MIT",
|
|
11
|
-
"version": "0.12.
|
|
11
|
+
"version": "0.12.3",
|
|
12
12
|
"main": "LexicalMarkdown.js",
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"lexical": "0.12.
|
|
14
|
+
"lexical": "0.12.3"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@lexical/utils": "0.12.
|
|
18
|
-
"@lexical/code": "0.12.
|
|
19
|
-
"@lexical/text": "0.12.
|
|
20
|
-
"@lexical/rich-text": "0.12.
|
|
21
|
-
"@lexical/list": "0.12.
|
|
22
|
-
"@lexical/link": "0.12.
|
|
17
|
+
"@lexical/utils": "0.12.3",
|
|
18
|
+
"@lexical/code": "0.12.3",
|
|
19
|
+
"@lexical/text": "0.12.3",
|
|
20
|
+
"@lexical/rich-text": "0.12.3",
|
|
21
|
+
"@lexical/list": "0.12.3",
|
|
22
|
+
"@lexical/link": "0.12.3"
|
|
23
23
|
},
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|