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